<style>
.informative-bg {
  margin: 1.5em 0 1em;
  padding: 1em;
  margin-top: 1em;
  background: #efe;
  border: green 1px dotted;
}
@media (prefers-color-scheme: dark) {
  .informative-bg {
    background: rgba(255, 255, 255, .05);
  }
}

div.informative-bg *:last-child {
  margin-bottom: 0;
}

div.informative-bg p:first-child {
  margin-top: 0;
}

div.informative-bg h2,
div.informative-bg h3,
div.informative-bg h4 {
  background: none;
}

.attributes::before, .methods::before,
.parameters::before, .exceptions::before,
.constructors::before, .members::before {
  font: bold 100% sans-serif;
  text-align: left;
  margin: 1.33em 0px;
  color: var(--heading-text, #005A9C);
}

.attributes::before { content: 'Attributes' }
.methods::before { content: 'Methods' }
.parameters::before { content: 'Parameters' }
.exceptions::before { content: 'Exceptions' }
.constructors::before { content: 'Constructors' }
.members::before { content: 'Dictionary members' }

.param,
.exceptionname,
.estype,
.esvalue {
  font-weight: bold;
}

.formula {
  display: block;
  margin: .5em 2em;
}
</style>

<pre class=metadata>
Title: Web Animations Module Level 1
Group: CSSWG
Shortname: web-animations
Status: ED
Level: 1
Work Status: Refining
ED: https://drafts.csswg.org/web-animations-1/
TR: https://www.w3.org/TR/web-animations-1/
Previous version: https://www.w3.org/TR/2023/WD-web-animations-1-20230605/
Previous version: https://www.w3.org/TR/2021/WD-web-animations-1-20220908/
Previous version: https://www.w3.org/TR/2021/WD-web-animations-1-20210518/
Previous version: https://www.w3.org/TR/2018/WD-web-animations-1-20181011/
Previous version: https://www.w3.org/TR/2016/WD-web-animations-1-20160913/
Previous version: https://www.w3.org/TR/2015/WD-web-animations-1-20150707/
Previous version: https://www.w3.org/TR/2014/WD-web-animations-20140605/
Previous version: https://www.w3.org/TR/2013/WD-web-animations-20130625/
Version history: https://github.com/w3c/csswg-drafts/commits/main/web-animations-1
Editor: Brian Birtles 43194, Invited Expert, brian@birchill.co.jp
Editor: Robert Flack 98451, Google, flackr@google.com
Editor: Stephen McGruer 96463, Google, smcgruer@google.com
Editor: Antoine Quint 51377, Apple Inc, graouts@apple.com
Former Editor: Shane Stephens 47691, Google, shans@google.com
Former Editor: Douglas Stockwell, Google, dstockwell@google.com
Former Editor: Alex Danilo 31960, Google, adanilo@google.com
Former Editor: Tab Atkins 42199, Google, jackalmage@gmail.com
Abstract: This specification defines a model for synchronization and timing
          of changes to the presentation of a Web page.
          It also defines an application programming interface (API)
          for interacting with this model
          and it is expected that other specifications will define
          declarative means for exposing these features.
!Participate: <a href="https://github.com/w3c/csswg-drafts/tree/main/web-animations-1">Fix the text through GitHub</a>
!Participate: Join the "waapi" channel on the <a href="https://damp-lake-50659.herokuapp.com/">Animation at Work</a> slack
!Participate: IRC: <a href="ircs://irc.w3.org:6667/webanimations">#webanimations</a> on W3C's IRC
Repository: w3c/csswg-drafts
Ignored Terms: double, boolean, unsigned long, unrestricted double, (unrestricted double or DOMString)
Ignored Vars: did seek, synchronously notify, auto-rewind
Markup Shorthands: markdown yes
Include Mdn Panels: no
WPT Path Prefix: web-animations
WPT Display: open
</pre>
<pre class=anchors>
urlPrefix: https://webidl.spec.whatwg.org/#dfn-; type: dfn; spec: webidl
    text: nullable; url: nullable-type
    text: convert ecmascript to idl value
urlPrefix: https://webidl.spec.whatwg.org/; type: dfn; spec: webidl
    text: a new promise
    text: create a new resolved Promise; url: a-promise-resolved-with
    text: [EnforceRange]; url: EnforceRange
    text: es to dictionary
    text: es to DOMString; url: es-to-DOMString
    text: DOMString to es; url: DOMString-to-es
    text: reject a promise; url: reject
    text: resolve a promise; url: resolve
urlPrefix: http://www.ecma-international.org/ecma-262/6.0/#sec-; type: dfn; spec: ecma-262
    text: code realms
    text: completion record specification type
    text: execution contexts
    text: EnumerableOwnNames
    text: GetIterator
    text: GetMethod
    text: IteratorStep
    text: IteratorValue
    text: Promise object; url: promise-objects
    text: Promise; url: promise-objects
    text: Type; url: ecmascript-data-types-and-values
    text: well known symbols
    text: [[DefineOwnProperty]]; url: ordinary-object-internal-methods-and-internal-slots-defineownproperty-p-desc
    text: [[Get]]; url: ordinary-object-internal-methods-and-internal-slots-get-p-receiver
urlPrefix: https://html.spec.whatwg.org/multipage/browsers.html; type: dfn; spec: html
    text: active document
    text: being rendered
    text: document associated with a window; url: concept-document-window
    text: an entry with persisted user state
    text: session history entry
urlPrefix: https://html.spec.whatwg.org/multipage/webappapis.html; type: dfn; spec: html
    text: current global object
    text: document.open(); url: dom-document-open
    text: DOM manipulation task source
    text: event loop processing model
    text: queue a task
    text: queue a microtask
    text: relevant Realm; url: concept-relevant-realm
    text: update the rendering
urlPrefix: https://html.spec.whatwg.org/multipage/webappapis.html; type: interface; spec: html
    text: EventHandler
urlPrefix: https://html.spec.whatwg.org/multipage/imagebitmap-and-animations.html.html; type: dfn; spec: html
    text: animation frame callbacks; url: animation-frames
    text: run the animation frame callbacks
urlPrefix: https://html.spec.whatwg.org/multipage/embedded-content.html; type: dfn; spec: html
    text: media element
urlPrefix: https://dom.spec.whatwg.org/; type: dfn; spec: dom
    text: create an event; url: concept-event-create
    text: dispatch; url: concept-event-dispatch
    text: constructing events
    text: node document; url: concept-node-document
url: https://html.spec.whatwg.org/#document; type: interface; text: Document; spec: html
url: https://svgwg.org/svg2-draft/pservers.html#StopElementOffsetAttribute; type: element-attr; for: stop; text: offset; spec: svg2
url: https://svgwg.org/svg2-draft/mimereg.html#mime-registration; type: dfn; text: SVG MIME type; spec: svg2
urlPrefix: https://drafts.csswg.org/cssom/; type: dfn; spec: cssom
    text: CSS property to IDL attribute
    text: IDL attribute to CSS property
    text: serialize a CSS value
urlPrefix: https://drafts.csswg.org/css-transitions/; type: dfn; spec: css-transitions-1
    text: events from CSS transitions; url: transition-events
    text: transitionend
urlPrefix: https://drafts.csswg.org/css-transitions-2/; type: dfn; spec: css-transitions-2
    text: owning element (transition); url: owning-element
urlPrefix: https://drafts.csswg.org/css-animations/; type: dfn; spec: css-animations-1
    text: events from CSS animations; url: events
urlPrefix: https://drafts.csswg.org/css-animations-2/; type: dfn; spec: css-animations-2
    text: owning element (animation); url: owning-element
urlPrefix: https://drafts.csswg.org/css-writing-modes-4/; type: dfn; spec: css-writing-modes-4
    text: equivalent physical property; url: logical-to-physical
urlPrefix: https://drafts.csswg.org/css-style-attr/; type: dfn; spec: css-style-attr
    text: style attribute
urlPrefix: https://drafts.csswg.org/web-animations-2/; type: dfn; spec: web-animations-2
    text: iteration composite operation
    text: iteration composite operation accumulate
urlPrefix: https://drafts.css-houdini.org/css-properties-values-api-1/; type: dfn; spec: css-properties-values-api-1
    text: syntax definition
    text: universal syntax definition
</pre>
<pre class="link-defaults">
spec:cssom-1; type: dfn;
    text: CSS declaration block
spec:css-backgrounds-3; type:property;
    text:background-image
    text:border-width
    text:border-bottom-width
    text:border-left-width
    text:border-right-width
    text:border-top-width
    text:border-top-color
    text:border-top
    text:border-color
    text:box-shadow
spec:css-cascade-5; type:dfn;
    text:computed value
    text:shorthand property
spec:css-color-4; type:value; text:transparent
spec:css-display-4; type:property;
    text:visibility
    text:display
spec:css-fonts-4; type:property;
    text:font-size
    text:font-weight
spec:css-transforms-1; type:property; text:transform
spec:css-values-4; type:dfn; text:interpolation
spec:dom; type:interface; text:DocumentOrShadowRoot
spec:dom; type:interface; text:EventTarget
spec:dom; type:interface; text:Event
spec:dom; type:dfn; text:descendant
spec:dom; type:dfn; for:/; text:document
spec:dom; type:dfn; for:/; text:shadow root
spec:infra; type:dfn; text:list
spec:infra; type:dfn; for:list; text:extend

</pre>

<script type="text/x-mathjax-config">
  MathJax.Hub.Config({showMathMenu: false});
</script>
<script src="https://www.w3.org/scripts/MathJax/2/MathJax.js?config=MML_SVG"></script>

Introduction {#introduction}
============

<div class=informative-bg>
<em>This section is non-normative</em>

  This specification defines a model
  (the <dfn export>Web Animations model</dfn>)
  for supporting animation and synchronization on the Web platform.
  It is intended that other specifications will build on this model
  and expose its features through declarative means.

  In addition, this specification also defines
  a programming interface to the model
  (the <dfn export>Web Animations <abbr title="Application Programming Interface">API</abbr></dfn>,
    defined in [[#programming-interface]])
  that may be implemented by user agents that provide support for scripting.

Use cases {#use-cases}
---------

  The [=Web Animations model=] is intended to provide the features necessary
  for expressing CSS Transitions [[CSS-TRANSITIONS-1]],
  CSS Animations [[CSS-ANIMATIONS-1]], and
  SVG [[SVG11]].
  As such, the use cases of the [=Web Animations model=] are
  the union of use cases for those three specifications.

  The use cases for the [=Web Animations API=] include the following:

  : Inspecting running animations
  ::
      Often Web applications need to wait for certain animated effects to complete
      before updating some state.
      The [=Web Animations API=] allows such applications
      to wait for all currently running animation to complete,
      regardless of whether they are defined
      by CSS Transitions, CSS Animations, SVG animations,
      or created directly using the [=Web Animations API=].

      <div class=example>
        <pre highlight=javascript>
          // Wait until all animations have finished before removing the element
          Promise.all(
            elem.getAnimations().map(animation => animation.finished)
          ).then(() => elem.remove());
        </pre>
      </div>

      Alternatively, applications can query the playback state of animations
      without waiting.

      <div class=example>
        <pre highlight=javascript>
          const isAnimating = elem.getAnimations().some(
            animation => animation.playState === 'running'
          );
        </pre>
      </div>

  : Controlling running animations
  ::
      It is sometimes useful to perform [=playback control=] on animations
      so that they can respond to external inputs.
      For example, it might be necessary to pause all existing animations
      before displaying a modal dialog
      so that they do not distract the user's attention.

      <div class=example>
        <pre highlight=javascript>
          // Pause all existing animations in the document
          for (const animation of document.getAnimations()) {
            animation.pause()
          }
        </pre>
      </div>

  : Creating animations from script
  ::
      While it is possible to use ECMAScript to perform animation using
      <code>requestAnimationFrame</code> [[!HTML]],
      such animations behave differently to declarative animation
      in terms of how they are represented in the CSS cascade
      and the performance optimizations that are possible,
      such as performing the animation on a separate thread.
      Using the [=Web Animations API=],
      it is possible to create animations from script
      that have the same behavior and performance characteristics
      as declarative animations.

      <div class=example>
        <pre highlight=javascript>
          // Fade out quickly
          elem.animate({ transform: 'scale(0)', opacity: 0 }, 300);
        </pre>
      </div>

  : Animation debugging
  ::
      In a complex application, it can be difficult
      to determine how an element arrived in its present state.
      The [=Web Animations API=] can be used
      to inspect running animations to answer questions such as,
      “Why is the opacity of this element changing?”

      <div class=example>
        <pre highlight=javascript>
          // Print the id of any opacity animations on elem
          for (const animation of elem.getAnimations()) {
            if (
              animation.effect instanceof KeyframeEffect &&
              animation.effect
                .getKeyframes()
                .some(frame =&gt; frame.hasOwnProperty('opacity'))
            ) {
              console.log(animation.id);
            }
          }
        </pre>
      </div>

      Likewise, in order to fine tune animations, it is often necessary
      to reduce their playback rate and replay them.

      <div class=example>
        <pre highlight=javascript>
          // Slow down and replay any transform animations
          const transformAnimations = elem.getAnimations().filter(
            animation =&gt;
              animation.effect instanceof KeyframeEffect &&
              animation.effect.getKeyframes().some(
                frame =&gt; frame.hasOwnProperty('transform')
              )
          );

          for (const animation of transformAnimations) {
            animation.currentTime = 0;
            animation.updatePlaybackRate(0.5);
          }
        </pre>
      </div>

  : Testing animations
  ::
      In order to test applications that make use of animations it is often
      impractical to wait for such animations to run to completion.
      Rather, it is desirable to seek the animations to specific times.

      <div class=example>
        <pre highlight=javascript>
          // Seek to the half-way point of an animation and check that the opacity is 50%
          for (const animation of elem.getAnimations()) {
            const { delay, activeDuration } = animation.effect.getComputedTiming();
            animation.currentTime = delay + activeDuration / 2;
          }
          assert.strictEqual(getComputedStyle(elem).opacity, '0.5');

          // Check that the loading screen is hidden after the animations finish
          for (const animation of elem.getAnimations()) {
            animation.finish();
          }
          // Wait one frame so that event handlers have a chance to run
          requestAnimationFrame(() =&gt; {
            assert.strictEqual(
              getComputedStyle(document.querySelector('#loading')).display, 'none');
          });
        </pre>
      </div>

Relationship to other specifications {#relationship-to-other-specifications}
------------------------------------

  CSS Transitions [[CSS-TRANSITIONS-1]],
  CSS Animations [[CSS-ANIMATIONS-1]],
  and SVG [[SVG11]]
  all provide mechanisms that generate animated content on a Web page.
  Although the three specifications provide many similar features,
  they are described in different terms.
  This specification proposes an abstract animation model
  that encompasses the common features of all three specifications.
  This [=Web Animations model=] is backwards-compatible
  with the current behavior of these specifications
  such that they can be defined in terms of this model without any observable change.

  The animation features in SVG 1.1 are defined
  in terms of SMIL Animation [[SMIL-ANIMATION]].
  It is intended that by defining SVG's animation features
  in terms of the [=Web Animations model=],
  the dependency between SVG and SMIL Animation can be removed.

  As with [=animation frame callbacks=]
  (commonly referred to as "requestAnimationFrame") [[HTML]],
  the [=Web Animations API=]
  allows animations to be created from script.
  The animations created using the [=Web Animations API=], however,
  once created, are executed entirely by the user agent,
  meaning they share the same performance characteristics
  as animations defined declaratively.
  Using this interface it is possible to create animations
  from script in a simpler and more performant manner.

  The time values used within the [=Web Animations API=]
  correspond with those used in [=animation frame callbacks=] [[HTML]]
  and their execution order is defined
  such that the two interfaces can be used simultaneously without conflict.

  The [=Web Animations API=] component of this specification
  makes some additions to interfaces defined in HTML [[!HTML]].

Overview of this specification {#overview-of-this-specification}
------------------------------

  This specification begins by defining an abstract model for animation,
  the [=Web Animations model=].
  This is followed by a programming interface, [=Web Animations API=],
  defined in terms of the abstract model.
  The programming interface is only relevant
  to user agents that provide scripting support.
</div>

Specification conventions {#spec-conventions}
=========================

  This specification begins by describing abstract concepts--
  such as [=animations=] and [=animation effects=]--
  and properties that belong to them,
  such as their [=playback rate=] or [=iteration duration=].
  In addition to these properties,
  there are often specific procedures for updating these properties,
  such as the procedure to [=set the playback rate=]
  or the procedure to [=set the start time=] of an animation.

  Where this specification does not specifically link to a procedure,
  text that requires the user agent to update a property,
  such as “make |animation|'s [=start time=] [=unresolved=]”,
  should be understood to refer to updating the property directly
  <em>without</em> invoking any related procedure.

  Further conventions not specific to this specification
  are described in [[#w3c-conventions]].

Web Animations model overview {#web-animations-model-overview}
=============================

  At a glance, the [=Web Animations model=] consists
  of two largely independent pieces:
  a [=timing model=] and an [=animation model=].
  The roles of these pieces are as follows:

  : <dfn id="timing-model-dfn">timing model</dfn>
  ::
      Takes a moment in time and converts it to a proportional distance
      within a single iteration of an animation,
      called the [=iteration progress=].
      The current [=iteration index=] is also recorded
      since some animations vary each time they repeat.
      The [=Web Animations timing model=] is defined in [[#timing-model]].

  : <dfn id="animation-model-dfn">animation model</dfn>.
  ::
      Takes the [=iteration progress=] and [=iteration index=] values
      produced by the [=timing model=]
      and converts them into a series of corresponding values
      to apply to the [=target properties=].
      The [=Web Animations animation model=] is defined in [[#animation-model]].

<div class=informative-bg>
<em>This section is non-normative</em>

  Graphically, this flow can be represented as follows:
  <figure>
    <img src="images/timing-and-animation-models.svg" width="600"
      alt="Overview of the operation of the Web Animations model.">
    <figcaption>
      Overview of the operation of the [=Web Animations model=].<br>
      The current time is input to the [=timing model=]
      which produces an [=iteration progress=] value and an [=iteration index=].<br>
      These parameters are used as input to the [=animation model=]
      which produces the [=target property=] values to apply.
    </figcaption>
  </figure>

  For example, consider an animation that:

  * starts after 3 seconds,
  * runs twice,
  * takes 2 seconds every time, and
  * changes the width of a rectangle from 50 pixels to 100 pixels.

  The first three points describe the [=timing model=]:
  at a time of 6 seconds, it calculates that the animation should be
  half-way through its second iteration
  and produces the result 0.5.
  The animation model then uses that information to calculate a width.

  This specification begins with the [[#timing-model|timing model]]
  and then proceeds to the [[#animation-model|animation model]].
</div>

<!--
          ████████ ████ ██     ██ ████ ██    ██  ██████
             ██     ██  ███   ███  ██  ███   ██ ██    ██
             ██     ██  ████ ████  ██  ████  ██ ██
             ██     ██  ██ ███ ██  ██  ██ ██ ██ ██   ████
             ██     ██  ██     ██  ██  ██  ████ ██    ██
             ██     ██  ██     ██  ██  ██   ███ ██    ██
             ██    ████ ██     ██ ████ ██    ██  ██████
-->

Timing model {#timing-model}
============

  This section describes and defines the behavior
  of the <dfn>Web Animations [=timing model=]</dfn>.

  Timing in the [=Web Animations model=] is represented through
  a hierarchy of relationships between <dfn>timing nodes</dfn>,
  in which parent nodes provide timing information to their child nodes
  in the form of [=time values=],
  ultimately resulting in an [=iteration progress=] and [=iteration index=]
  supplied to the [=animations model=]

Timing model characteristics {#timing-model-overview}
----------------------------

<div class=informative-bg>
<em>This section is non-normative</em>

  Two features characterize the Web Animations timing model:
  it is <em>stateless</em> and it is <em>hierarchical</em>.

### Stateless ### {#stateless}

  The Web Animations [=timing model=] operates
  by taking an input [=time value=]
  and producing an output [=iteration progress=].
  Since the output is based solely on the input time
  and is independent of previous inputs,
  the model can be described as stateless.
  This gives the model the following properties:

  : Frame-rate independent
  ::
      Since the output is independent of previous inputs,
      the rate at which the model is updated
      will not affect its progress.
      Provided the input times
      are proportional to the progress of real-world time,
      animations will progress at an identical rate
      regardless of the capabilities of the device running them.

  : Direction-agnostic
  ::
      Since the sequence of inputs is insignificant,
      the model is directionless.
      This means that the model can be updated to an arbitrary moment
      without requiring any specialized handling.

  : Constant-time seeking
  ::
      Since each input is independent of the previous input,
      the processing required to perform a seek operation,
      even far into the future,
      is at least potentially constant.

  There are a few exceptions to the stateless behavior of the timing model.

  Firstly, a number of methods defined in
  the [[#programming-interface|programming interface]] to the model
  provide play control such as pausing an animation.
  These methods are defined in terms of the time at which they are called
  and are therefore stative.
  These methods are provided primarily for convenience
  and are not part of the core timing model,
  but are layered on top.

  Similarly, the
  [[#reaching-the-end|finishing behavior]] of animations
  means that dynamic changes to
  the end time of the media ([=associated effect=]) of an animation
  can produce a different result
  depending on when the change occurs.
  This behavior is somewhat unfortunate
  but has been deemed intuitive and consistent with HTML.
  As a result, the model can only truly be described as stateless
  <em>in the absence of dynamic changes to its timing properties</em>.

  Finally, each time the model is updated,
  it can be considered to establish a temporary state.
  While this temporary state affects the values returned
  from the [[#programming-interface|programming interface]],
  it has no influence on the subsequent updates
  and hence does not conflict with the stateless qualities described above.

### Hierarchical ### {#hierarchical}

  The other characteristic feature of the timing model
  is that time is inherited.
  Time begins at a timeline
  and cascades down a number of steps to each animation effect.
  At each step, time can be shifted backwards or forwards,
  scaled, reversed, paused, and repeated.

  <figure>
    <img src="images/time-hierarchy.svg" width="350"
              alt="A hierarchy of timing nodes">
    <figcaption>
      A hierarchy of timing nodes.
      Each node in the tree derives its time from its parent node.
    </figcaption>
  </figure>

  In this level of the specification the hierarchy is shallow.
  A subsequent level of this specification
  will introduce the concept of group effects
  which allows for deeper timing hierarchies.

</div>

Time values {#time-value-section}
-----------

  A <dfn>time value</dfn> in the [=Web Animations model=]
  is a value that serves the purpose of synchronization.
  [=Time values=] are real numbers that nominally represent
  a number of milliseconds from some moment.
  However, the connection between [=time values=] and wall-clock milliseconds
  can be obscured by any number of transformations applied to the value
  as it passes through the time hierarchy.

  Note: In the future there could be timelines
  that are based on scroll position or UI gestures
  in which case the connection between time values and milliseconds
  will be weakened even further.

  A [=time value=] can be <dfn>unresolved</dfn>,
  i.e. represent the absence of a meaningful [=time value=].
  This can happen if
  a [=timing node=] is not in a state to produce a [=time value=].

Timelines {#timelines}
---------

  A <dfn export>timeline</dfn> is a [=timing node=]
  that provides a source of [=time values=].
  At any given moment, a [=timeline=] has a single current [=time value=]
  known simply as the timeline's <dfn export for=timeline>current time</dfn>.
  Changes in a [=timeline=]’s [=timeline/current time=]
  are ultimately what drive [=animations=] in the [=Web Animations model=].

  A [=timeline=] might not always be able to return a meaningful [=time value=],
  but only an [=unresolved=] time value.
  For example, its [=timeline/current time=] might be defined relative to
  a moment that has yet to occur,
  such as the firing of a document's load event.
  A [=timeline=] is considered to be
  <dfn export lt="inactive timeline">inactive</dfn>
  when its [=time value=] is [=unresolved=],
  and <dfn export lt="active timeline">active</dfn> otherwise.

  A [=timeline=] is
  <dfn export lt="monotonically increasing timeline" local-lt="monotonically increasing">monotonically increasing</dfn>
  if its reported [=timeline/current time=] is always greater than or equal to
  its previously reported [=timeline/current time=].

  Specific types of [=timelines=] may define a procedure to
  <dfn lt="timeline time to origin-relative time" export>convert
  a timeline time to an origin-relative time</dfn>
  for [=time value=] <var ignore>time</var>,
  so that the [=time values=] produced by wallclock-based timelines
  can be compared.

  A [=timeline=] can be
  <dfn lt="timeline associated with a document">associated with a document</dfn>.

### Document timelines ### {#document-timelines}

  A <dfn export>document timeline</dfn> is a type of [=timeline=]
  that is [=timeline associated with a document|associated with a document=]
  and whose [=timeline/current time=] is calculated
  as a fixed offset from the |now| timestamp provided
  each time the [=update animations and send events=] procedure is run.
  This fixed offset is equal to
  the [=timeline/current time=] of the [=default document timeline=]
  when this timeline’s [=timeline/current time=] was zero,
  and is thus referred to as
  the document timeline's <dfn>origin time</dfn>.

  Issue(2079): There must be a better term than "origin time"&mdash;
               it's too similar to "time origin".

  Prior to establishing the [=time origin=] for its associated document,
  a [=document timeline=] is [=inactive timeline|inactive=].

  After a [=document timeline=] becomes [=active timeline|active=],
  it is [=monotonically increasing=].

  A [=document timeline=] that is associated
  with a {{Document}} that is not an [=active document=]
  is also considered to be [=inactive timeline|inactive=].

  To <a lt="timeline time to origin-relative time">convert
  a timeline time, |timeline time|, to an origin-relative time</a>
  for a document timeline, |timeline|,
  return the sum of the |timeline time| and |timeline|'s [=origin time=].
  If |timeline| is inactive, return an [=unresolved=] [=time value=].

#### The default document timeline #### {#the-documents-default-timeline}

  Each {{Document}} has a [=document timeline=] called the
  <dfn export for="document">default document timeline</dfn>.
  The [=default document timeline=] is unique to each document
  and persists for the lifetime of the document,
  including calls to [=document.open()=] [[!HTML]].

  The [=default document timeline=] has an [=origin time=] of zero.

#### Relationship to wall-clock time #### {#document-wallclock-time}

<div class=informative-bg>
<em>This section is non-normative</em>

  Since no scaling is applied to
  the |now| timestamp values provided to a [=document timeline=],
  the [=time values=] it produces will be
  proportional to wall-clock milliseconds.

  Furthermore, since the [=time values=]
  of the [=default document timeline=]
  have a zero offset from the [=time origin=],
  <code>document.timeline.currentTime</code> will roughly correspond
  to <a href="https://www.w3.org/TR/hr-time/#dom-performance-now"><code>Performance.now()</code></a> [[HR-TIME]]
  with the exception that <code>document.timeline.currentTime</code>
  does not change in between calls
  to the [=update animations and send events=] procedure.

</div>

Animation Frames {#animation-frame-loop}
----------------

  <div algorithm>
    When asked to <dfn export>update animations and send events</dfn>
    for a {{Document}} |doc| at timestamp |now|,
    run these steps:

    1. Update the [=timeline/current time=] of all timelines
        <a lt="timeline associated with a document">associated with |doc|</a>
        passing |now| as the timestamp.

        <div class=note>
          Due to the hierarchical nature of the timing model,
          updating the [=timeline/current time=] of a [=timeline=] also involves:

          * Updating the [=animation/current time=] of any [=animations=]
              [=associated with a timeline|associated with=] the timeline.

          * Running the [=update an animation's finished state=] procedure
              for any animations whose [=animation/current time=] has been updated.

          * Queueing [=animation events=] for any such animations.

        </div>

    1. [=Remove replaced animations=] for |doc|.

    1. [=Perform a microtask checkpoint=].

        Note: This is to ensure that any microtasks queued up
        as a result of resolving or rejecting Promise objects
        as part of updating timelines in the previous step,
        run their callbacks prior to dispatching animation events.

    1. Let |events to dispatch| be a copy of |doc|'s [=pending animation event queue=].

    1. Clear |doc|'s [=pending animation event queue=].

    1. Perform a stable sort of the [=animation events=] in |events to dispatch|
        as follows:

        1. Sort the events by their [=scheduled event time=]
            such that events that were scheduled to occur earlier
            sort before events scheduled to occur later,
            and events whose scheduled event time is [=unresolved=]
            sort before events with a [=resolved=]
            scheduled event time.

        1. Within events with equal [=scheduled event times=],
            sort by their [=composite order=].

            Note: The purpose of sorting events is to ensure that, as best possible,
            even on devices with differing capabilities
            and hence different frame rates,
            events are dispatched in a consistent order.

            Note: The requirement for the sort to be a stable sort
            is because sometimes multiple events can be queued
            with the same scheduled event time.
            For example, a CSS animation with a duration of zero would dispatch
            both an <code>animationstart</code> and an <code>animationend</code> event
            with the same scheuled event time,
            and the order of these events should be preserved.

    1. [=Dispatch=] each of the events in |events to dispatch| at their
        corresponding target using the order established in the previous step.
  </div>

  It is often convenient to describe each time this procedure is invoked
  as establishing a new <dfn export>animation frame</dfn>.
  Changes to the timing properties of [=animations=] or [=animation effects=],
  or the addition and removal of the objects can
  cause the output of the timing or animation model to change,
  but these operations in themselves do not create a new [=animation frame=];
  rather they merely update the current [=animation frame=].

Animations {#animations}
----------

  An <dfn export id="concept-animation">animation</dfn>
  is a [=timing node=] that
  binds an [=animation effect=] child,
  called its <dfn export for=animation>associated effect</dfn>,
  to a [=timeline=] parent so that it runs.
  Both of these associations are optional and configurable
  such that an [=animation=] can have
  no [=associated effect=] or [=timeline=] at a given moment.

  [=Animations=] also allow run-time control of the connection
  between the [=animation effect=] and its [=timeline=],
  through <dfn>playback control</dfn> functions such as
  [[#pausing-an-animation-section|pausing]],
  [[#setting-the-current-time-of-an-animation|seeking]],
  and [[#speed-control|speed control]].

  [=Time values=] flow from the [=timeline=] through the [=animation=]
  to the [=associated effect=].
  The [=time value=] provided to an [=animation=]’s [=associated effect=]
  is called the [=animation=]’s <dfn export for=animation>current time</dfn>.

  Note: The relationship between an animation and an [=animation effect=]
  is analogous to that of a DVD player and a DVD.

  In addition to its [=timeline=], [=associated effect=],
  and [=animation/current time=]
  an [=animation=] has the following:

  <dl export dfn-for="animation">
  : <dfn>document for timing</dfn>
  ::
      The {{Document}} with which the [=animation=]’s [=timeline=] is
      [=timeline associated with a document|associated=].
      If an animation is not associated with a timeline,
      or its timeline is not associated with a document,
      then it has no [=document for timing=].

  : <dfn>start time</dfn>
  ::
      The [=time value=] of its [=timeline=]
      when its [=associated effect=] is scheduled to begin playback.
      An animation's start time is initially [=unresolved=].

  : <dfn>hold time</dfn>
  ::
      A [=time value=],
      which is used to freeze the animation's [=animation/current time=] output
      in circumstances such as pausing.
      The [=hold time=] is initially [=unresolved=].

  </dl>

  In order to establish the relative ordering of conflicting [=animations=],
  animations are appended to a <dfn export>global animation list</dfn>
  in the order in which they are created.
  Certain [=animation class|classes of animations=], however,
  may provide alternative means of ordering animations
  (see [[#animation-classes]]).

### Calculating the current time of an animation ### {#the-current-time-of-an-animation}

  The [=animation/current time=] of an [=animation=] is calculated from
  the first matching condition below:

  <dl class=switch>

  : If the animation's [=hold time=] is [=unresolved|resolved=],
  ::
      The [=animation/current time=] is the animation's [=hold time=].

  : If <em>any</em> of the following are true:
    * the animation has no associated [=timeline=], or
    * the associated [=timeline=] is [=inactive timeline|inactive=], or
    * the animation's [=start time=] is [=unresolved=],
  ::
      The [=animation/current time=] is an [=unresolved=] time value.

  : Otherwise,
  ::
      <blockquote>
        <code><a for="animation">current time</a> =
          (<var>timeline time</var> − <a>start time</a>)
          × <a>playback rate</a></code>
      </blockquote>

      Where |timeline time| is the current [=time value=]
      of the associated [=timeline=].
      The [=playback rate=] value is defined in [[#speed-control]].

  </dl>

### Setting the timeline of an animation ### {#setting-the-timeline}

  <div algorithm>
    The procedure to
    <dfn export for=animation>set the timeline of an animation</dfn>,
    |animation|,
    to |new timeline| which may be null,
    is as follows:

    1. Let |old timeline| be
        the current [=timeline=] of |animation|, if any.

    1. If |new timeline| is the same object as |old timeline|,
        abort this procedure.

    1. Let the [=timeline=] of |animation| be
        |new timeline|.

    1. If the [=start time=] of |animation| is [=unresolved|resolved=],
        make |animation|'s [=hold time=] [=unresolved=].

        Note: This step ensures that the [=finished play state=] of |animation|
        is not “sticky”,
        but is re-evaluated based on its updated [=animation/current time=].

    1. Run the procedure to
        [=update an animation's finished state=] for |animation|
        with the |did seek| flag set to false,
        and the |synchronously notify| flag set to false.
  </div>

<h4 id="setting-the-associated-effect" oldids="setting-the-target-effect">
Setting the associated effect of an animation</h4>

  <div algorithm>

    The procedure to <dfn export for=animation>set the associated effect of an animation</dfn>,
    |animation|,
    to |new effect| which may be null, is as follows:

    1. Let |old effect| be
        the current [=associated effect=] of |animation|, if any.

    1. If |new effect| is the same object as |old effect|,
        abort this procedure.

    1. If |animation| has a [=pending pause task=],
        reschedule that task to run as soon as |animation| is [=ready=].

    1. If |animation| has a [=pending play task=],
        reschedule that task to run as soon as
        |animation| is [=ready=] to play |new effect|.

    1. If |new effect| is not <code>null</code>
        and if |new effect| is the [=associated effect=]
        of another [=animation=], |previous animation|,
        run the procedure to [=set the associated effect of an animation=]
        (this procedure)
        on |previous animation|,
        passing null as |new effect|.

    1. Let the [=associated effect=] of |animation| be
        |new effect|.

    1. Run the procedure to [=update an animation's finished state=]
        for |animation| with the |did seek| flag set to false,
        and the |synchronously notify| flag set to false.

  </div>

### Setting the current time of an animation ### {#setting-the-current-time-of-an-animation}

  The [=animation/current time=] of an [=animation=] can be set to a new value
  to <dfn>seek</dfn> the animation.
  The procedure for setting the current time is defined in two parts.

  <div algorithm>
    The procedure to <dfn export for=animation>silently set the current time</dfn>
    of an animation, |animation|,
    to |seek time| is as follows:

    1. If |seek time| is an [=unresolved=] time value,
        then perform the following steps.

        1. If the [=animation/current time=] is [=resolved=],
            then [=throw=] a <span class=exceptionname>TypeError</span>.

        1. Abort these steps.

    1. Update either |animation|'s [=hold time=] or
        [=start time=] as follows:

        <dl class=switch>

        : If <em>any</em> of the following conditions are true:
            * |animation|'s [=hold time=] is
                [=unresolved|resolved=], or
            * |animation|'s [=start time=]
                is [=unresolved|unresolved=], or
            * |animation| has no associated [=timeline=] or the
                associated [=timeline=] is
                [=inactive timeline|inactive=], or
            * |animation|'s [=playback rate=] is 0,
        ::
            Set |animation|'s [=hold time=] to |seek time|.

        : Otherwise,
        ::
            Set |animation|'s [=start time=] to the result of evaluating
            <code><var>timeline time</var> − (<var>seek time</var> / <a>playback rate</a>)</code>
            where |timeline time| is the current [=time value=]
            of the [=timeline=] associated with |animation|.

        </dl>

    1. If |animation| has no associated [=timeline=]
        or the associated [=timeline=] is [=inactive timeline|inactive=],
        make |animation|'s [=start time=] [=unresolved=].

        Note: This preserves the invariant that
        when we don't have an active timeline
        it is only possible to set <em>either</em> the [=start time=]
        <em>or</em> the animation's [=animation/current time=].

    1. Make |animation|'s [=previous current time=] [=unresolved=].
  </div>

  <div algorithm>
    The procedure to <dfn export for=animation>set the current time</dfn>
    of an animation, |animation|,
    to |seek time| is as follows:

    1. Run the steps to [=silently set the current time=] of |animation|
        to |seek time|.
    1. If |animation| has a [=pending pause task=],
        synchronously complete the pause operation
        by performing the following steps:
        1. Set |animation|'s [=hold time=] to |seek time|.
        1. [=Apply any pending playback rate=] to |animation|.
        1. Make |animation|'s [=start time=] [=unresolved=].
        1. Cancel the [=pending pause task=].
        1. [=resolve a Promise|Resolve=]
            |animation|'s [=current ready promise=]
            with |animation|.
    1. Run the procedure to [=update an animation's finished state=]
         for |animation|
         with the |did seek| flag set to true,
         and the |synchronously notify| flag set to false.
  </div>

### Setting the start time of an animation ### {#setting-the-start-time-of-an-animation}

  <div algorithm>
    The procedure to <dfn>set the start time</dfn>
    of an [=animation=], |animation|,
    to |new start time|
    is as follows:

    1. Let |timeline time| be the current [=time value=]
        of the [=timeline=] that |animation| is associated with.
        If there is no [=timeline=] associated with |animation|
        or the associated timeline is [=inactive timeline|inactive=],
        let the |timeline time| be [=unresolved=].

    1. If |timeline time| is [=unresolved=]
        and |new start time| is [=unresolved|resolved=],
        make |animation|'s [=hold time=] [=unresolved=].

        Note: This preserves the invariant that
        when we don't have an active timeline
        it is only possible to set <em>either</em> the [=start time=]
        <em>or</em> the animation's [=animation/current time=].

    1. Let |previous current time| be
        |animation|'s [=animation/current time=].

        Note: This is the [=animation/current time=]
        after applying the changes from the previous step,
        which can cause the current time to become [=unresolved=].

    1. [=Apply any pending playback rate=] on |animation|.

    1. Set |animation|'s [=start time=] to |new start time|.

    1. Update |animation|'s [=hold time=] based on
        the first matching condition from the following:

        <dl class=switch>

        : If |new start time| is [=unresolved|resolved=],
        ::
            If |animation|'s [=playback rate=] is not zero,
            make |animation|'s [=hold time=] [=unresolved=].

        : Otherwise (|new start time| is [=unresolved=]),
        ::
            Set |animation|'s [=hold time=] to |previous current time|
            even if |previous current time| is [=unresolved=].

        </dl>

    1. If |animation| has a [=pending play task=] or a [=pending pause task=],
        cancel that task and [=resolve a Promise|resolve=]
        |animation|'s [=current ready promise=]
        with |animation|.

    1. Run the procedure to [=update an animation's finished state=]
        for |animation|
        with the |did seek| flag set to true,
        and the |synchronously notify| flag set to false.
  </div>

<h4 id="waiting-for-the-associated-effect" oldids="waiting-for-the-target-effect">
Waiting for the associated effect</h4>

<div class=informative-bg>
<em>This section is non-normative</em>

  Some operations performed by an [=animation=]
  might not occur instantaneously.
  For example, some user agents might delegate the playback of an animation
  to a separate process or to specialized graphics hardware,
  each of which could incur some setup overhead.

  If such an animation is timed
  from the moment when the animation was triggered
  there can be a significant jump
  between the first and second frames of the animation
  corresponding to the setup time involved.

  To avoid this problem,
  Web Animations typically begins timing animations
  from the moment when the first frame of the animation is complete.
  This is represented by an [=unresolved=] [=start time=] on the [=animation=]
  which becomes resolved when the animation is [=ready=].
  Content can opt out of this behavior by setting
  the [=start time=] to a [=unresolved|resolved=] [=time value=].

</div>

  An animation is <dfn>ready</dfn> at the first moment
  where <em>both</em> of the following conditions are true:

  * the user agent has completed any setup required
      to begin the playback of the animation's [=associated effect=],
      including rendering the first frame of any [=keyframe effect=].

  * the animation is associated with a [=timeline=]
      that is not [=inactive timeline|inactive=].

### The current ready promise ### {#the-current-ready-promise}

  Each [=animation=] has a <dfn>current ready promise</dfn>.
  The [=current ready promise=] is initially a resolved [=Promise=]
  created using the procedure to [=create a new resolved Promise=]
  with the animation itself as its value
  and created in the [=relevant Realm=] of the animation.

  The object is replaced with a new [=Promise object=]
  every time the animation queues
  a [=pending play task=] or a [=pending pause task=]
  when it previously did not have a pending task,
  or when the animation is canceled
  (see [[#canceling-an-animation-section]]).

  <div class=note>

    Note that since the same object is used for both
    pending play and pending pause requests,
    authors are advised to check the state of the animation
    when the [=Promise object=] is resolved.

    For example, in the following code fragment,
    the state of the animation will be [=play state/running=]
    when the [=current ready promise=] is resolved.
    This is because the <code>play</code> operation occurs
    while a [=pending play task=] is still queued
    and hence the [=current ready promise=] is re-used.

    <div class=example>
      <pre highlight=javascript>
        animation.pause();
        animation.ready.then(function() {
          // Displays 'running'
          alert(animation.playState);
        });
        animation.play();
      </pre>
    </div>

  </div>

### Playing an animation ### {#playing-an-animation-section}

  <div algorithm="play an animation">
    The procedure to <dfn>play an animation</dfn>, |animation|,
    given a flag |auto-rewind|,
    is as follows:

    1. Let |aborted pause| be a boolean flag
        that is true if |animation| has a [=pending pause task=],
        and false otherwise.
    1. Let |has pending ready promise| be a boolean flag
        that is initially false.
    1. Let |seek time| be a [=time value=]
        that is initially [=unresolved=].

    1. If the |auto-rewind| flag is true,
        perform the steps corresponding to the <em>first</em> matching condition
        from the following, if any:

        <dl class=switch>

        : If |animation|'s [=effective playback rate=] ≥ 0,
            and |animation|'s [=animation/current time=] is <em>either</em>:
            * [=unresolved=], or
            * less than zero, or
            * greater than or equal to [=associated effect end=],
        ::
            Set |seek time| to zero.

        : If |animation|'s [=effective playback rate=] < 0,
            and |animation|'s [=animation/current time=] is <em>either</em>:
            * [=unresolved=], or
            * less than or equal to zero, or
            * greater than [=associated effect end=],
        ::
            <dl class=switch>

            : If [=associated effect end=] is positive infinity,
            ::
                [=throw=] an "{{InvalidStateError}}" {{DOMException}}
                and abort these steps.

            : Otherwise,
            ::
                Set |seek time| to |animation|'s [=associated effect end=].

            </dl>

        </dl>

    1. If the following three conditions are <em>all</em> satisfied:
        * |seek time| is [=unresolved=], and
        * |animation|'s [=start time=] is [=unresolved=], and
        * |animation|'s [=animation/current time=] is [=unresolved=],

        set |seek time| to zero.

        Note: The above step ensures that this procedure will play an idle animation
        regardless of the setting of the |auto-rewind| flag.

    1. Let |has finite timeline| be true if |animation|
        has an associated [=timeline=] that is not [=monotonically increasing=].

    1. If |seek time| is [=resolved=],

        <div class=switch>

        : If |has finite timeline| is true,
        ::
            1. Set |animation|'s [=start time=] to |seek time|.
            1. Let |animation|'s [=hold time=] be [=unresolved=].
            1. [=Apply any pending playback rate=] on |animation|.

        : Otherwise,
        ::
            Set |animation|'s [=hold time=] to |seek time|.

        </div>

    1. If |animation|'s [=hold time=] is [=unresolved|resolved=],
        let its [=start time=] be [=unresolved=].

    1. If |animation| has a [=pending play task=] or a [=pending pause task=],

        1. Cancel that task.
        1. Set |has pending ready promise| to true.

    1. If the following four conditions are <em>all</em> satisfied:

        * |animation|'s [=hold time=] is [=unresolved=], and
        * |seek time| is [=unresolved=], and
        * |aborted pause| is false, and
        * |animation| does <em>not</em> have a [=pending playback rate=],

        abort this procedure.

    1. If |has pending ready promise| is false,
        let |animation|'s [=current ready promise=] be
        [=a new promise=] in the [=relevant Realm=] of |animation|.

    1. Schedule a task to run as soon as |animation| is [=ready=].
        The task shall perform the following steps:

        1. Assert that at least one of |animation|'s [=start time=] or [=hold time=]
            is [=unresolved|resolved=].

        1. Let |ready time| be the [=time value=] of
            the [=timeline=] associated with |animation|
            at the moment when |animation| became [=ready=].

        1. Perform the steps corresponding to the first matching condition below,
            if any:

            <dl class=switch>

            : If |animation|'s [=hold time=] is [=unresolved|resolved=],
            ::
                1. [=Apply any pending playback rate=] on |animation|.

                1. Let |new start time| be the result of evaluating
                    <code><var>ready time</var> − <a>hold time</a>
                          / <a>playback rate</a></code>
                    for |animation|.
                    If the [=playback rate=] is zero,
                    let |new start time| be simply |ready time|.

                1. Set the [=start time=] of |animation| to |new start time|.

                1. If |animation|'s [=playback rate=] is not 0,
                    make |animation|'s [=hold time=] [=unresolved=].

            : If |animation|'s [=start time=] is resolved
                and |animation| has a [=pending playback rate=],

            ::
                1. Let |current time to match| be the result of evaluating
                    <code>(<var>ready time</var> − <a>start time</a>)
                          × <a>playback rate</a></code>
                    for |animation|.

                1. [=Apply any pending playback rate=] on |animation|.

                1. If |animation|'s [=playback rate=] is zero,
                    let |animation|'s [=hold time=] be |current time to match|.

                1. Let |new start time| be the result of evaluating
                    <code><var>ready time</var> − <var>current time to match</var>
                          / <a>playback rate</a></code>
                    for |animation|.
                    If the [=playback rate=] is zero,
                    let |new start time| be simply |ready time|.

                1. Set the [=start time=] of |animation| to |new start time|.

            </dl>

        1. [=resolve a promise|Resolve=] |animation|'s [=current ready promise=]
            with |animation|.

        1. Run the procedure to [=update an animation's finished state=]
            for |animation|
            with the |did seek| flag set to false,
            and the |synchronously notify| flag set to false.

            Note: The order of the above two steps is important since
            it means that an animation with zero-length [=associated effect=]
            will resolve its [=current ready promise=]
            before its [=current finished promise=].

        So long as the above task is scheduled but has yet to run,
        |animation| is described as having a <dfn>pending play task</dfn>.
        While the task is running, however,
        |animation| does <em>not</em> have a [=pending play task=].

        If a user agent determines that |animation| is immediately [=ready=],
        it may schedule the above task as a microtask
        such that it runs at the next [=perform a microtask checkpoint|microtask checkpoint=],
        but it <em>must not</em> perform the task synchronously.

        <div class=note>

          The above requirement to run the [=pending play task=] asynchronously
          ensures that code such as the following
          behaves consistently between implementations:

          <div class=example>
            <pre highlight=javascript>
              animation.play();
              animation.ready.then(
                () => { console.log('Playback commenced'); },
                () => { console.log('Playback was canceled'); }
              );
              // Suppose some condition requires playback to be canceled...
              animation.cancel();
              // "Playback was canceled" will be printed to the console.
            </pre>
          </div>

          In the above code, were the [=pending play task=] run synchronously,
          the [=current ready promise=] would not be rejected.

        </div>

    1. Run the procedure to [=update an animation's finished state=]
        for |animation|
        with the |did seek| flag set to false,
        and the |synchronously notify| flag set to false.
  </div>

### Pausing an animation ### {#pausing-an-animation-section}

  Whenever an [=animation=] has an [=unresolved=] [=start time=],
  its [=animation/current time=] will be suspended.

  As with [=play an animation|playing an animation=],
  pausing might not happen instantaneously
  (see [[#waiting-for-the-associated-effect]]).
  For example, if animation is performed by a separate process,
  it might be necessary to synchronize the [=animation/current time=]
  to ensure that it reflects the state drawn by the animation process.

  <div algorithm="pause an animation">
    The procedure to <dfn>pause an animation</dfn>, |animation|,
    is as follows:

    1. If |animation| has a [=pending pause task=],
        abort these steps.
    1. If the [=play state=] of |animation| is [=play state/paused=],
        abort these steps.
    1. Let |seek time| be
        a [=time value=] that is initially [=unresolved=].
    1. Let |has finite timeline| be true
        if |animation| has an associated [=timeline=]
        that is not [=monotonically increasing=].

    1. If the |animation|'s [=animation/current time=] is [=unresolved=],
        perform the steps according to the first matching condition below:

        <dl class=switch>

        : If |animation|'s [=playback rate=] is ≥ 0,
        ::
            Set |seek time| to zero.

        : Otherwise,
        ::
            <dl class=switch>

            : If [=associated effect end=] for |animation| is positive infinity,
            ::
                [=throw=] an "{{InvalidStateError}}" {{DOMException}}
                and abort these steps.

            : Otherwise,
            ::
                Set |seek time| to |animation|'s [=associated effect end=].

            </dl>

        </dl>

    1. If |seek time| is [=unresolved|resolved=],

            <div class=switch>

            : If |has finite timeline| is true,
            ::
                Set |animation|'s [=start time=] to |seek time|.

            : Otherwise,
            ::
                Set |animation|'s [=hold time=] to |seek time|.

            </div>

    1. Let |has pending ready promise| be a boolean flag
         that is initially false.

    1. If |animation| has a [=pending play task=],
        cancel that task
        and let |has pending ready promise| be true.

    1. If |has pending ready promise| is false,
        set |animation|'s [=current ready promise=] to
        [=a new promise=] in the [=relevant Realm=] of |animation|.

    1. Schedule a task to be executed at the first possible moment
        where <em>both</em> of the following conditions are true:

        * the user agent has performed any processing necessary to suspend
            the playback of |animation|'s [=associated effect=], if any.
        * the animation is associated with a [=timeline=]
            that is not [=inactive timeline|inactive=].

        The task shall perform the following steps:

        1. Let |ready time| be the time value of
            the timeline associated with |animation|
            at the moment when the user agent completed processing necessary
            to suspend playback of |animation|'s [=associated effect=].

        1. If |animation|'s [=start time=] is [=unresolved|resolved=]
            and its [=hold time=] is <em>not</em> resolved,
            let |animation|'s [=hold time=] be the result of evaluating
            <code>(<var>ready time</var> − <a>start time</a>)
                  × <a>playback rate</a></code>.

            Note: The [=hold time=] might be already set
            if the animation is [=play state/finished=],
            or if the animation has a [=pending play task=].
            In either case we want to preserve the [=hold time=]
            as we enter the [=play state/paused=] state.

        1. [=Apply any pending playback rate=] on |animation|.

        1. Make |animation|'s [=start time=] unresolved.

        1. [=resolve a Promise|Resolve=] |animation|'s [=current ready promise=]
            with |animation|.

        1. Run the procedure to [=update an animation's finished state=]
            for |animation|
            with the |did seek| flag set to false,
            and the |synchronously notify| flag set to false.

        So long as the above task is scheduled but has yet to run,
        |animation| is described as having a <dfn>pending pause task</dfn>.
        While the task is running, however,
        |animation| does <em>not</em> have a [=pending pause task=].

        As with the [=pending play task=],
        the user agent must run the [=pending pause task=] asynchronously,
        although that could be as soon as the next
        [=perform a microtask checkpoint|microtask checkpoint=].

    1. Run the procedure to [=update an animation's finished state=]
        for |animation|
        with the |did seek| flag set to false,
        and the |synchronously notify| flag set to false.
  </div>

### Reaching the end ### {#reaching-the-end}

<div class=informative-bg>
<em>This section is non-normative</em>

  DVD players or cassette players typically continue playing
  until they reach the end of their media at which point they stop.
  If such players are able to play in reverse,
  they typically stop playing when they reach the beginning of their media.
  In order to emulate this behavior,
  and to provide consistency with HTML's [=media elements=] [[HTML]],
  the [=animation/current time=] of Web Animations' animations
  do not play forwards beyond the
  [=animation effect/end time=] of their [=associated effect=]
  or play backwards past time zero.

  An animation that has reached the natural boundary of its playback range
  is said to have <em>finished</em>.

  Graphically, the effect of limiting the current time is shown below.

  <figure>
    <img src="images/limiting.svg" width="500"
         alt="The effect of limiting the current time of an animation.">
    <figcaption>
      The effect of limiting the [=animation/current time=] of an [=animation=]
      with a start time of 1s,
      an [=associated effect=] of length 3s,
      and a positive [=playback rate=].
      After the current time of the animation reaches
      the end of the associated effect,
      it is capped at 3s.
    </figcaption>
  </figure>

  It is possible, however, to [=seek=]
  the [=animation/current time=] of an [=animation=]
  to a time past the end of the [=associated effect=].
  When doing so, the current time will not progress
  but the animation will act as if it had been paused
  at the seeked time.

  This allows, for example, [=seeking=]
  the [=animation/current time=] of an animation
  with <em>no</em> [=associated effect=] to 5s.
  If [=associated effect=] with an [=animation effect/end time=] later than 5s
  is later associated with the animation,
  playback will begin from the 5s mark.

  Similar behavior to the above scenario can arise
  when the length of an animation's [=associated effect=] changes.

  Similarly, when the [=playback rate=] is negative,
  the [=animation/current time=] does not progress past time zero.

</div>

### The current finished promise ### {#the-current-finished-promise}

  Each animation has a <dfn>current finished promise</dfn>.
  The [=current finished promise=] is initially
  a pending [=Promise=] object.

  The object is replaced with a new [=promise=]
  every time the animation leaves the [=finished play state=].

### Updating the finished state ### {#updating-the-finished-state}

  For an animation with a positive [=playback rate=],
  the [=animation/current time=] continues to increase
  until it reaches the [=associated effect end=].

  The <dfn>associated effect end</dfn> of an animation
  is equal to the [=animation effect/end time=] of the animation's [=associated effect=].
  If the animation has no [=associated effect=],
  the [=associated effect end=] is zero.

  For an animation with a negative [=playback rate=],
  the [=animation/current time=] continues to decrease
  until it reaches zero.

  A running animation that has reached this boundary (or overshot it)
  and has a [=unresolved|resolved=] [=start time=]
  is said to be [=play state/finished=].

  The crossing of this boundary
  is checked on each modification to the animation object
  using the procedure to [=update an animation's finished state=] defined below.
  This procedure is also run
  as part of the [=update animations and send events=] procedure.
  In both cases the |did seek| flag, defined below,
  is set to false.

  For each animation,
  the user agent maintains a <dfn>previous current time</dfn> [=time value=]
  that is originally [=unresolved=].

  Whilst during normal playback
  the [=animation/current time=] of an [=animation=]
  is limited to the boundaries described above,
  it is possible to [=seek=] the current time of an animation
  to times outside those boundaries
  using the procedure to [=set the current time=] of an animation.

  <div algorithm="update animation finished state">

    The procedure to <dfn>update an animation's finished state</dfn>
    for |animation|,
    given a flag |did seek|
    (to indicate if the update is being performed
     after [=setting the current time=]),
    and a flag |synchronously notify|
    (to indicate the update was called
     in a context where we expect finished event queueing
     and finished promise resolution to happen immediately,
     if at all)
    is as follows:

    1. Let the |unconstrained current time| be
        the result of calculating the [=animation/current time=],
        substituting an [=unresolved=] time value for the [=hold time=]
        if |did seek| is false.
        If |did seek| is true,
        the |unconstrained current time|
        is equal to the [=animation/current time=].

        Note: This is required to accommodate timelines that can change direction.
        Without this definition, a once-finished animation would remain finished
        even when its timeline progresses in the opposite direction.

    1. If <em>all three</em> of the following conditions are true,

        * the |unconstrained current time| is [=unresolved|resolved=],
            <em>and</em>
        * |animation|'s [=start time=] is [=unresolved|resolved=],
            <em>and</em>
        * |animation| does <em>not</em> have
            a [=pending play task=] or a [=pending pause task=],

        then update |animation|'s [=hold time=] based on
        the first matching condition for |animation| from below, if any:

        <dl class=switch>

        : If [=playback rate=] > 0
            and |unconstrained current time| is
            greater than or equal to [=associated effect end=],
        ::
            If |did seek| is true,
            let the [=hold time=] be the value of |unconstrained current time|.

            If |did seek| is false,
            let the [=hold time=] be the maximum value
            of [=previous current time=] and [=associated effect end=].
            If the [=previous current time=] is [=unresolved=],
            let the [=hold time=] be [=associated effect end=].

        : If [=playback rate=] < 0
            and |unconstrained current time| is less than or equal to 0,
        ::
            If |did seek| is true,
            let the [=hold time=] be the value of |unconstrained current time|.

            If |did seek| is false,
            let the [=hold time=] be the minimum value
            of [=previous current time=] and zero.
            If the [=previous current time=] is [=unresolved=],
            let the [=hold time=] be zero.

        : If [=playback rate=] ≠ 0,
            and |animation| is associated with an [=active timeline=],
        ::
            Perform the following steps:

            1. If |did seek| is true
                and the [=hold time=] is [=unresolved|resolved=],
                let |animation|'s [=start time=] be equal to
                the result of evaluating
                <code><var>timeline time</var>
                      − (<a>hold time</a> / <a>playback rate</a>)</code>
                where |timeline time| is the current [=time value=] of
                the [=timeline=] associated with |animation|.

            1. Let the [=hold time=] be [=unresolved=].

        </dl>

    1. Set the [=previous current time=] of |animation| to be
        the result of calculating its [=animation/current time=].

    1. Let |current finished state| be true
         if the [=play state=] of |animation| is [=play state/finished=].
        Otherwise, let it be false.

    1. If |current finished state| is true
        and the [=current finished promise=] is not yet resolved,
        perform the following steps:

        1. Let <dfn>finish notification steps</dfn> refer to
            the following procedure:

            1. If |animation|'s [=play state=]
                is not equal to [=play state/finished=],
                abort these steps.
            1. [=resolve a promise|Resolve=]
                |animation|'s [=current finished promise=] object
                with |animation|.
            1. [=create an event|Create=]
                an {{AnimationPlaybackEvent}}, |finishEvent|.
            1. Set |finishEvent|'s {{Event/type}} attribute
                to [=finish event|finish=].
            1. Set |finishEvent|'s {{AnimationPlaybackEvent/currentTime}} attribute
                to the [=animation/current time=] of |animation|.
            1. Set |finishEvent|'s {{AnimationPlaybackEvent/timelineTime}} attribute
                to the [=timeline/current time=]
                of the [=timeline=] with which |animation| is associated.
                If |animation| is not associated with a timeline,
                or the timeline is [=inactive timeline|inactive=],
                let {{AnimationPlaybackEvent/timelineTime}} be
                <code class=esvalue>null</code>.
            1. If |animation| has a [=document for timing=],
                then append |finishEvent|
                to its [=document for timing=]'s [=pending animation event queue=]
                along with its target, |animation|.
                For the [=scheduled event time=],
                use the result of
                [=animation time to origin-relative time|converting=]
                |animation|'s [=associated effect end=]
                to an origin-relative time.

                Otherwise,
                [=queue a task=] to [=dispatch=] |finishEvent| at |animation|.
                The task source for this task is
                the [=DOM manipulation task source=].

        1. If |synchronously notify| is true,
            cancel any queued microtask to run
            the [=finish notification steps=] for this |animation|,
            and run the [=finish notification steps=] immediately.

            Otherwise,
            if |synchronously notify| is false,
            [=queue a microtask=]
            to run [=finish notification steps=] for |animation|
            unless there is already a microtask queued
            to run those steps for |animation|.

    1. If |current finished state| is false
        and |animation|'s [=current finished promise=] is already resolved,
        set |animation|'s [=current finished promise=] to
        [=a new promise=] in the [=relevant Realm=] of |animation|.
  </div>

  <div class=note>

    Typically, notification about the finished state of an animation
    is performed asynchronously.
    This allows for the animation to temporarily enter the [=finished play state=]
    without triggering events to be fired or promises to be resolved.

    For example, in the following code fragment,
    <code>animation</code> temporarily enters the finished state.
    If notification of the finished state occurred synchronously,
    this code would cause the [=finish event=] to be queued
    and the [=current finished promise=] to be resolved.
    However, if we reverse the order of the two statements
    such that the <code>iterations</code> is updated first,
    this would not happen.
    To avoid this surprising behavior,
    notification about the finished state of an animation
    is typically performed asynchronously.

    <div class=example>
      <pre highlight=javascript>
        var animation = elem.animate({ left: '100px' }, 2000);
        animation.playbackRate = 2;
        animation.currentTime = 1000; // animation is now finished
        animation.effect.updateTiming({ iterations: 2 }); // animation is no longer finished
      </pre>
    </div>

    The one exception to this asynchronous behavior
    is when the [=finish an animation=] procedure is performed
    (typically by calling the {{Animation/finish()}} method).
    In this case the author's intention to finish the animation is clear
    so the notification about the finished state of the animation
    occurs synchronously as demonstrated below.

    <div class=example>
      <pre highlight=javascript>
        var animation = elem.animate({ left: '100px' }, 1000);
        animation.finish(); // finish event is queued immediately and finished promise
                            // is resolved despite the fact that the following statement
                            // causes the animation to leave the finished state
        animation.currentTime = 0;
      </pre>
    </div>

    Note that, like the procedure to [=finish an animation=],
    the procedure to [=cancel an animation=]
    similarly queues the [=cancel event=]
    and rejects the [=current finished promise=] and [=current ready promise=]
    in a <em>synchronous</em> manner.
  </div>

### Finishing an animation ### {#finishing-an-animation-section}

  <div algorithm>
    An animation can be advanced
    to the natural end of its current playback direction
    by using the procedure to <dfn>finish an animation</dfn> for |animation|
    defined below:

    1. If |animation|'s [=effective playback rate=] is zero,
        or if |animation|'s [=effective playback rate=] > 0
        and [=associated effect end=] is infinity,
        [=throw=] an "{{InvalidStateError}}" {{DOMException}}
        and abort these steps.

    1. [=Apply any pending playback rate=] to |animation|.

    1. Set |limit| as follows:

        <div class=switch>

        : If [=playback rate=] > 0,
        ::
            Let |limit| be [=associated effect end=].

        : Otherwise,
        ::
            Let |limit| be zero.

        </div>

    1. [=Silently set the current time=] to |limit|.

    1. If |animation|'s [=start time=] is [=unresolved=]
        and |animation| has an associated [=active timeline=],
        let the [=start time=] be the result of evaluating
        <code><var>timeline time</var>
              − (<var>limit</var> / <a>playback rate</a>)</code>
        where |timeline time| is the current [=time value=]
        of the associated [=timeline=].

      1. If there is a [=pending pause task=]
          and [=start time=] is [=unresolved|resolved=],

        1. Let the [=hold time=] be [=unresolved=].

            Note: Typically the [=hold time=] will already be unresolved
            except in the case when
            the animation was previously [=play state/idle=].

        1. Cancel the [=pending pause task=].

        1. [=resolve a Promise|Resolve=] the [=current ready promise=]
            of |animation| with |animation|.

    1. If there is a [=pending play task=]
        and [=start time=] is [=unresolved|resolved=],
        cancel that task and [=resolve a Promise|resolve=]
        the [=current ready promise=] of |animation|
        with |animation|.

    1. Run the procedure to [=update an animation's finished state=]
        for |animation|
        with the |did seek| flag set to true,
        and the |synchronously notify| flag set to true.
  </div>

### Canceling an animation ### {#canceling-an-animation-section}

  An animation can be canceled
  which causes the [=animation/current time=] to become [=unresolved=],
  hence removing any effects caused by the [=associated effect=].

  <div algorithm>
    The procedure to <dfn>cancel an animation</dfn> for |animation|
    is as follows:

    1. If |animation|'s [=play state=] is <em>not</em> [=play state/idle=],
        perform the following steps:

        1. Run the procedure to [=reset an animation's pending tasks=]
            on |animation|.
        1. [=reject a Promise|Reject=] the [=current finished promise=]
            with a {{DOMException}} named "{{AbortError}}".
        1. Set the \[[PromiseIsHandled]] internal slot
            of the [=current finished promise=]
            to true.
        1. Let [=current finished promise=] be
            [=a new promise=] in the [=relevant Realm=] of |animation|.
        1. [=create an event|Create=]
            an {{AnimationPlaybackEvent}}, |cancelEvent|.
        1. Set |cancelEvent|'s {{Event/type}} attribute
            to [=cancel event|cancel=].
        1. Set |cancelEvent|'s {{AnimationPlaybackEvent/currentTime}}
            to <code class=esvalue>null</code>.
        1. Let |timeline time| be the [=timeline/current time=]
            of the [=timeline=] with which |animation| is associated.
            If |animation| is not associated with an [=active timeline=],
            let |timeline time| be an [=unresolved=] [=time value=].
        1. Set |cancelEvent|'s {{AnimationPlaybackEvent/timelineTime}}
            to |timeline time|.
            If |timeline time| is [=unresolved=],
            set it to <code class=esvalue>null</code>.
        1. If |animation| has a [=document for timing=],
            then append |cancelEvent| to
            its [=document for timing=]'s [=pending animation event queue=]
            along with its target, |animation|.
            If |animation| is associated with an [=active timeline=]
            that defines a procedure to
            [=timeline time to origin-relative time|convert
            timeline times to origin-relative time=],
            let the [=scheduled event time=] be
            the result of applying that procedure to |timeline time|.
            Otherwise, the [=scheduled event time=] is
            an [=unresolved=] [=time value=].

            Otherwise,
            [=queue a task=] to [=dispatch=] |cancelEvent| at |animation|.
            The task source for this task is
            the [=DOM manipulation task source=].

    1. Make |animation|'s [=hold time=] [=unresolved=].
    1. Make |animation|'s [=start time=] [=unresolved=].
  </div>

  <div algorithm>
    The procedure to
    <dfn export for=animation>reset an animation's pending tasks</dfn>
    for |animation| is as follows:

    1. If |animation| does not have
        a [=pending play task=] or a [=pending pause task=],
        abort this procedure.

    1. If |animation| has a [=pending play task=],
        cancel that task.

    1. If |animation| has a [=pending pause task=],
        cancel that task.

    1. [=Apply any pending playback rate=] on |animation|.

    1. [=reject a Promise|Reject=]
        |animation|'s [=current ready promise=]
        with a {{DOMException}} named "{{AbortError}}".

    1. Set the \[[PromiseIsHandled]] internal slot of |animation|'s
        [=current ready promise=] to true.

    1. Let |animation|'s [=current ready promise=] be the result of
        [=create a new resolved Promise|creating a new resolved Promise object=]
        with value |animation|
        in the [=relevant Realm=] of |animation|.
  </div>

### Speed control ### {#speed-control}

<div class=informative-bg>
  The rate of play of an animation can be controlled
  by setting its [=playback rate=].
  For example, setting a playback rate of 2 will cause
  the animation's [=animation/current time=]
  to increase at twice the rate of its [=timeline=].
  Similarly, a playback rate of -1 will cause
  the animation's [=animation/current time=] to decrease
  at the same rate as the [=time values=] from its [=timeline=] increase.
</div>

  [=Animations=] have a <dfn>playback rate</dfn> that provides a scaling factor
  from the rate of change of the associated [=timeline=]’s [=time values=]
  to the animation's [=animation/current time=].
  The [=playback rate=] is initially 1.

  Setting an animation's [=playback rate=] to zero
  effectively pauses the animation
  (however, the [=play state=] does not necessarily become [=play state/paused=]).

#### Setting the playback rate of an animation #### {#setting-the-playback-rate-of-an-animation}

  <div algorithm>
    The procedure to <dfn>set the playback rate</dfn>
    of an [=animation=], |animation|,
    to |new playback rate|
    is as follows:

    1. Clear any [=pending playback rate=] on |animation|.

    1. Let |previous time| be
        the value of the [=animation/current time=] of |animation|
        before changing the [=playback rate=].

    1. Let |previous playback rate| be
        the current [=effective playback rate=] of |animation|.

    1. Set the [=playback rate=] to |new playback rate|.

    1. Perform the steps corresponding to
        the <em>first</em> matching condition from the following, if any:

        <dl class=switch>

        : If |animation| is associated with
            a [=monotonically increasing=] [=timeline=]
            and the |previous time| is [=unresolved|resolved=],
        ::
            [=Set the current time=] of |animation| to |previous time|.

        : If |animation| is associated with a non-null [=timeline=]
            that is not [=monotonically increasing=],
            the [=start time=] of |animation| is [=resolved=],
            [=associated effect end=] is not infinity,
            and <em>either</em>:

            * the |previous playback rate| < 0
                and the |new playback rate| ≥ 0, or
            * the |previous playback rate| ≥ 0
                and the |new playback rate| < 0,

        ::  Set |animation|'s [=start time=] to the result of evaluating
            <code><a>associated effect end</a> − <a>start time</a></code>
            for |animation|.

            Note: This effectively flips the animation start/end times
            on non-monotonic timelines,
            preserving the relative offset of the start time
            from the other direction.

        </dl>
  </div>

#### Seamlessly updating the playback rate of an animation #### {#seamlessly-updating-the-playback-rate-of-an-animation}

  For an in-flight animation that is running on another process or thread,
  the procedure to [=set the playback rate=]
  can cause the animation to jump
  if the process or thread running the animation
  is not currently synchronized
  with the process or thread performing the update.

  In order to produce seamless changes to
  the [=playback rate=] of an [=animation=],
  animations may have a <dfn>pending playback rate</dfn>
  that defines a playback rate to be applied
  after any necessary synchronization has taken place
  (for the case of animations running in a different thread or process).

  Initially the [=pending playback rate=] of an [=animation=] is unset.

  The <dfn>effective playback rate</dfn> of an [=animation=] is
  its [=pending playback rate=], if set,
  otherwise it is the animation's [=playback rate=].

  <div algorithm>
    When an [=animation=], |animation|, is to
    <dfn>apply any pending playback rate</dfn>
    the following steps are performed:

    1. If |animation| does not have a [=pending playback rate=],
        abort these steps.

    1. Set |animation|'s [=playback rate=] to its [=pending playback rate=].

    1. Clear |animation|'s [=pending playback rate=].
  </div>

  <div algorithm>
    The procedure to <dfn>seamlessly update the playback rate</dfn>
    of an [=animation=], |animation|,
    to |new playback rate|
    preserving its [=animation/current time=]
    is as follows:

    1. Let |previous play state| be |animation|'s [=play state=].

        Note: It is necessary to record the play state
        before updating |animation|'s [=effective playback rate=] since,
        in the following logic,
        we want to immediately apply the [=pending playback rate=] of |animation|
        if it is <em>currently</em> [=play state/finished=]
        regardless of whether or not it will still be finished
        after we apply the [=pending playback rate=].

    1. Let |animation|'s [=pending playback rate=] be |new playback rate|.

    1. Perform the steps corresponding to
        the first matching condition below:

        <dl class=switch>

        : If |animation| has a [=pending play task=]
            or a [=pending pause task=],

        ::
            Abort these steps.

            Note: The different types of pending tasks will
            apply the [=pending playback rate=] when they run
            so there is no further action required in this case.

        : If |previous play state|
            is [=idle play state|idle=] or [=play state/paused=],
            or |animation|'s [=animation/current time=] is [=unresolved=],

        ::
            [=Apply any pending playback rate=] on |animation|.

            Note: The second condition above is required
            so that if we have a [=play state/running=] animation
            with an unresolved current time
            and no pending play task,
            we do not attempt to play it below.

        : If |previous play state| is [=play state/finished=],
        ::
            1. Let the |unconstrained current time| be
                the result of calculating
                the [=animation/current time=] of |animation|
                substituting an [=unresolved=] time value
                for the [=hold time=].

            1. Let |animation|'s [=start time=] be
                the result of evaluating the following expression:

                 <blockquote>
                   <code><var>timeline time</var>
                         − (<var>unconstrained current time</var>
                            / <a>pending playback rate</a>)</code>
                  </blockquote>

                Where |timeline time| is the current [=time value=] of
                the [=timeline=] associated with |animation|.

                If [=pending playback rate=] is zero,
                let |animation|'s [=start time=] be |timeline time|.

            1. [=Apply any pending playback rate=] on |animation|.

            1. Run the procedure to [=update an animation's finished state=]
                for |animation|
                with the |did seek| flag set to false,
                and the |synchronously notify| flag set to false.

        : Otherwise,

        ::
            Run the procedure to [=play an animation=] for |animation|
            with the |auto-rewind| flag set to false.

        </dl>
  </div>

### Reversing an animation ### {#reversing-an-animation-section}

  <div algorithm>
    The procedure to <dfn>reverse an animation</dfn>
    of [=animation=] |animation|
    is as follows:

    1. If there is no [=timeline=] associated with |animation|,
        or the associated [=timeline=] is [=inactive timeline|inactive=]
        [=throw=] an "{{InvalidStateError}}" {{DOMException}}
        and abort these steps.

    1. Let |original pending playback rate| be
        |animation|'s [=pending playback rate=].

    1. Let |animation|'s [=pending playback rate=] be
        the additive inverse of its [=effective playback rate=]
        (i.e. <code>-<a>effective playback rate</a></code>).

    1. Run the steps to [=play an animation=] for |animation|
        with the |auto-rewind| flag set to true.

        If the steps to [=play an animation=] throw an exception,
        set |animation|'s [=pending playback rate=]
        to |original pending playback rate|
        and propagate the exception.
  </div>

### Play states ### {#play-states}

  An [=animation=] can be described as being in one of the following
  <dfn lt="play state" export for="animation">play states</dfn>,
  for each of which a non-normative description is also provided:

<div class=informative-bg>

  : [=play state/idle=]
  ::
      The [=animation/current time=] of the animation is [=unresolved=]
      and the [=start time=] of the animation is [=unresolved=]
      and there are no pending tasks.
      In this state the animation has no effect.

  : [=play state/running=]
  ::
      The animation has a resolved [=animation/current time=]
      that changes on each [=animation frame=]
      (provided the [=playback rate=] is not zero
       and the [=timeline=] is [=active timeline|active=]
       and [=monotonically increasing=]).

  : [=play state/paused=]
  ::
      The animation has been suspended
      and the [=animation/current time=] is no longer changing.
  : [=play state/finished=]
  ::
      The animation has reached the natural boundary of its playback range
      and the [=animation/current time=] is no longer updating.

</div>

  The [=play state=] of [=animation=], |animation|, at a given moment
  is the state corresponding to
  the <em>first</em> matching condition from the following:

  <div class=switch>

  : <em>All</em> of the following conditions are true:
      * The [=animation/current time=] of |animation|
          is [=unresolved=],
          <em>and</em>
      * the [=start time=] of |animation| is [=unresolved=],
          <em>and</em>
      * |animation| does <em>not</em> have <em>either</em>
          a [=pending play task=] <em>or</em> a [=pending pause task=],
  ::
      &rarr; <dfn for="play state" local-lt="idle play state" export>idle</dfn>

  : <em>Either</em> of the following conditions are true:
      * |animation| has a [=pending pause task=], <em>or</em>
      * <em>both</em> the [=start time=] of |animation| is [=unresolved=]
          <em>and</em> it does <em>not</em> have a [=pending play task=],
  ::
      &rarr; <dfn for="play state" local-lt="paused play state" export>paused</dfn>

  : For |animation|,
      [=animation/current time=] is [=resolved=]
      and <em>either</em> of the following conditions are true:
      * |animation|'s [=effective playback rate=] > 0
          and [=animation/current time=] ≥ [=associated effect end=];
          <em>or</em>
      * |animation|'s [=effective playback rate=] < 0 and
          [=animation/current time=] ≤ 0,
  ::
      &rarr; <dfn for="play state" local-lt="finished play state" export>finished</dfn>

  : Otherwise,
  ::
      &rarr; <dfn for="play state" local-lt="running play state" export>running</dfn>

  </div>

  <div class=note>

    Note that the [=paused play state=] effectively “wins”
    over the [=finished play state=].

    However, an animation that is paused
    outside of its natural playback range
    can be converted from a [=play state/paused=] animation
    into a [=play state/finished=] animation
    without restarting by setting the [=start time=]
    such as below:

    <div class=example>
      <pre highlight=javascript>
        animation.effect.updateTiming({ duration: 5000 });
        animation.currentTime = 4000;
        animation.pause();
        animation.ready.then(function() {
          animation.effect.updateTiming({ duration: 3000 });
          alert(animation.playState); // Displays 'paused'
          animation.startTime =
            document.timeline.currentTime - animation.currentTime * animation.playbackRate;
          alert(animation.playState); // Displays 'finished'
        });
      </pre>
    </div>

  </div>

### Animation events ### {#animation-events-section}

  <dfn>Animation events</dfn> include
  the [=animation playback events=] defined in this specification
  as well as the [=events from CSS transitions=] [[CSS-TRANSITIONS-1]]
  and [=events from CSS animations=] [[CSS-ANIMATIONS-1]].
  Future specifications may extend this set
  with further types of [=animation events=].

  Each {{Document}} maintains a <dfn export>pending animation event queue</dfn>
  that stores [=animation events=]
  along with their corresponding event targets
  and <dfn>scheduled event time</dfn>.
  The [=scheduled event time=] is a [=time value=] relative to the [=time origin=]
  representing when the event would ideally have been dispatched
  were animations updated at an infinitely high frequency.
  It is used by the procedure to [=update animations and send events=]
  to sort queued [=animation events=] chronologically.
  Note that this value can be [=unresolved=] if, for example,
  the [=animation=]'s [=timeline=] produces values
  that are unrelated to the [=time origin=]
  (e.g. a timeline that tracks scroll-position)
  or if the [=timeline=] is [=inactive timeline|inactive=].

#### Sorting animation events #### {#sorting-animation-events}

  The following definitions are provided to assist with sorting queued events.

  <div algorithm>
    To <dfn lt="animation time to timeline time">convert
    an animation time to timeline time</dfn>
    a [=time value=], |time|, that is relative to
    the [=start time=] of an animation, |animation|,
    perform the following steps:

    1.  If |time| is [=unresolved=],
         return |time|.

    1.  If |time| is infinity,
         return an [=unresolved=] [=time value=].

    1.  If |animation|'s [=playback rate=] is zero,
         return an [=unresolved=] [=time value=].

    1.  If |animation|'s [=start time=] is [=unresolved=],
         return an [=unresolved=] [=time value=].

    1.  Return the result of calculating
         <code><var>time</var> × (1 / <var>playback rate</var>) +
               <var>start time</var></code>,
         where |playback rate| and |start time| are
         the [=playback rate=] and [=start time=] of |animation|,
         respectively.
  </div>

  <div algorithm>
    To <dfn lt="animation time to origin-relative time">convert
    a timeline time to an origin-relative time</dfn>
    a [=time value=], |time|, that is expressed in the same scale
    as the [=time values=] of a [=timeline=], <var ignore>timeline</var>,
    perform the following steps:

    1. Let |timeline time| be the result of
        [=animation time to timeline time|converting=] |time|
        from an animation time to a timeline time.

    1. If |timeline time| is [=unresolved=],
         return |time|.

    1. If |animation| is not associated with a [=timeline=],
         return an [=unresolved=] time value.

    1. If |animation| is associated with an [=inactive timeline=],
         return an [=unresolved=] time value.

    1. If there is no procedure
         to [=timeline time to origin-relative time|convert
         a timeline time to an origin-relative time=]
         for the timeline associated with |animation|,
         return an [=unresolved=] [=time value=].

    1. Return the result of
         [=timeline time to origin-relative time|converting=]
         |timeline time| to an origin-relative time
         using the procedure defined for
         the [=timeline=] associated with |animation|.
  </div>

#### Animation playback events #### {#animation-playback-events-section}

  As [=animations=] play, they report changes to their status through
  <dfn>animation playback events</dfn>.

  [=Animation playback events=] are a property of the timing model.
  As a result they are dispatched even when
  the [=associated effect=] of the [=animation=]
  is absent or has no observable result.

#### Types of animation playback events #### {#animation-playback-event-types}

  : <dfn lt="finish event">finish</dfn>
  ::
      Queued whenever an animation enters the [=finished play state=].

  : <dfn lt="cancel event">cancel</dfn>
  ::
      Queued whenever an animation enters the [=idle play state=]
      from another state.
      Creating a new [=animation=] that is initially idle
      does <em>not</em> generate a new [=cancel event=].

  : <dfn lt="remove event">remove</dfn>
  ::
      Queued whenever an animation is automatically removed.
      See [[#replacing-animations]].

Animation effects {#animation-effects}
-----------------

  An <dfn>animation effect</dfn> is a [=timing node=]
  that provides a static description of some timed behavior.

  All [=animation effects=] have the following properties:
  * an [=active interval=],
      determined by its [=start delay=] and [=active duration=],
      defining the time interval during which its behavior takes effect
  * an [=iteration duration=], [=iteration count=], and [=iteration start=]
      defining how its behavior repeats within that interval
  * a [=playback direction=] applying to each iteration,
      to allow reversing the timing of effects within an iteration
  * a [=fill mode=] defining the application of effects
      [=before phase|before=]/[=after phase|after=] its [=active interval=]
  * optionally, an [=animation effect/associated animation=]
      and through it, optionally, an [=associated with a timeline|associated timeline=],
      which cause the [=animation effect=] to apply its behavior
      by driving its [=local time|local time value=]

### Types of animation effects ### {#types-of-animation-effects}

  This specification defines a single type of [=animation effect=]:
  [=keyframe effects=].
  Subsequent levels of this specification
  will define further types of [=animation effects=].

### Associated animation and timeline ### {#animation-effects-and-animations}

  An [=animation effect=] is
  <dfn for="animation effect" lt="associated animation"
       local-lt="associated with an animation">associated with an animation</dfn>
  when the effect is that animation’s [=associated effect=].
  At a given moment,
  an [=animation effect=] can be [=associated animation|associated=]
  with at most one [=animation=].

  An [=animation effect=], |effect|,
  is <dfn>associated with a timeline</dfn>, |timeline|,
  if |effect| is [=associated with an animation=] which, in turn,
  is associated with |timeline|.

### Local time ### {#local-time-section}

  The <dfn>local time</dfn> of an [=animation effect=]
  represents the [=animation/current time=]
  provided by its [=associated animation=],
  determining the progress of the [=animation effect=].
  At a given moment,
  it is based on the first matching condition below:

  <div class=switch>

  : If the [=animation effect=] is [=associated with an animation=],
  ::
      the [=local time=] is the [=animation/current time=] of the [=animation=].

  : Otherwise,
  ::
      the [=local time=] is [=unresolved=].

  </div>

### Time spaces ### {#effect-time-spaces}

<div class=informative-bg>
<em>This section is non-normative</em>

  In Web Animations all times are relative to some point of reference.
  These different points of reference produce different <dfn>time spaces</dfn>.

  This can be compared to coordinate spaces
  as used in computer graphics.
  The zero time of a [=time space=] is analogous
  to the origin of a coordinate space.

  Within the [=Web Animations model=]
  we define progress of an [=animation effect=] on the basis of its [=active time=],
  which is a time relative to the beginning of its [=active interval=]--
  thus a time in the [=active time space=].

  Note: This time space is internal to the model
  and not exposed in the programming interface or in markup.

  We can further describe animations that repeat
  as establishing a new [=time space=]
  each time the animation repeats:
  the [=iteration time space=].

  The [=animation effect=] thus translates the [=animation/current time=]
  provided by the [=associated animation=]
  through a series of [=time spaces=]:
  * the <dfn noexport>local time space</dfn>,
      relative to the [=start time=] of the [=associated animation=],
      yielding the [=local time=]
  * the <dfn noexport>active time space</dfn>,
      relative to the start of the [=active interval=],
      yielding the [=active time=]
  * the <dfn noexport>iteration time space</dfn>,
      relative to the start of the [=animation effect=]’s current iteration,
      yielding the <dfn>iteration time</dfn>

  These time spaces are illustrated below.

  <figure>
    <img src="images/time-spaces.svg" width="600"
         alt="A comparison of local time, active time, and iteration time.
              Local time crosses zero at the start time of the animation,
              and rises linearly.
              Active time is zero until the start of the active interval,
              at which point it rises linearly to the end time,
              beyond which it remains at its maximum value.
              Iteration time is likewise zero until the start of the active interval,
              and rises linearly,
              but restarts at zero at the start of every new iteration,
              and remains at its halfway point from the end time onward.">
    <figcaption>
      A comparison of [=local time=], [=active time=], and [=iteration time=]
      for an animation with an [=iteration duration=] of 1s
      and an [=iteration count=] of 2.5.
      The [=animation/start time=] defined by the [=animation=]
      and [=animation effect/end time=] defined by the [=animation effect=]
      are also annotated.
    </figcaption>
  </figure>

  In addition to these time spaces
  we can also refer to the <dfn noexport>document time space</dfn>,
  which is time space of the [=time values=]
  of the [=default document timeline=] of the {{Document}}
  of the [=current global object=].

  Note: While the time spaces themselves are not bounded,
  Web Animations defines [=active time=] and the [=iteration progress=]
  such that they are clamped to a set range as shown in the diagram.
  For example, whilst a time of -1 second
  is a valid time in <em>active time space</em>,
  the procedure for calculating the [=active time=]
  defined in [[#calculating-the-active-time]]
  will never return a negative value.
</div>

### The active interval ### {#the-active-interval}

  [=Animation effects=] define an <dfn>active interval</dfn>,
  which is the period of time during which the effect
  is scheduled to produce its effect
  (excepting [=fill modes=],
  which apply outside the [=active interval=]).
  Each [=animation effect=] has only one such interval,
  which is defined by its [=start delay=] and [=active duration=].

  <div class=informative-bg>

    The relationship between
    the [=start time=], [=start delay=], and [=active duration=]
    is illustrated below.

    <figure>
      <img src="images/active-interval-examples.svg" width="600"
          alt="Examples of the effect of the start dela
               on the endpoints of the active interval">
      <figcaption>
        Examples of the effect of the [=start delay=]
        on the endpoints of the [=active interval=].<br>
        (a) An animation effect with no delay;
        the [=start time=] and beginning of the [=active interval=]
        are coincident.<br>
        (b) An animation effect with a positive delay;
        the beginning of the [=active interval=]
        is deferred by the delay.<br>
        (c) An animation effect with a negative delay;
        the beginning of the [=active interval=]
        is brought forward by the delay.
      </figcaption>
    </figure>
  </div>

#### The start delay #### {#the-start-delay}

  The lower bound of the [=active interval=]
  by default corresponds to the [=start time=] of the [=associated animation=],
  but can be shifted by the <dfn>start delay</dfn>,
  which is a signed offset from the [=start time=] of the [=animation=].

#### The active duration #### {#the-active-duration}

  The length of the [=active interval=] is called the <dfn>active duration</dfn>,
  and is determined by the [=iteration duration=] and [=iteration count=]
  as defined below.
  Its length determines the upper bound of the [=active interval=].

  <blockquote id="calculating-the-active-duration">
    [=active duration=] =
       <code><a>iteration duration</a> × <a>iteration count</a></code>
  </blockquote>

  If either the [=iteration duration=] or [=iteration count=] are zero,
  the [=active duration=] is zero.

  Note: This clarification is needed
  since the result of infinity multiplied by zero
  is undefined according to IEEE 754-2008.

#### The end delay and animation effect end time #### {#the-end-delay}

  Similar to the [=start delay=],
  an [=animation effect=] also has an <dfn>end delay</dfn>,
  which is primarily of use when sequencing one [=animation effect=]
  based on the [=animation effect/end time=] of another [=animation effect=].

  The <dfn for="animation effect">end time</dfn>,
  of an [=animation effect=]
  is the result of evaluating
  <code>max(<a>start delay</a> + <a>active duration</a> + <a>end delay</a>, 0)</code>.

  Note: Although the [=end delay=] is typically only useful
  in combination with sequence effects
  which are introduced in a subsequent level of this specification,
  it is included here for the purpose of representing
  the <a href="https://www.w3.org/TR/SVG/animate.html#MinAttribute"><code>min</code></a>
  attribute in SVG ([[SVG11]], Chapter 19).

### Animation effect phases and states ### {#animation-effect-phases-and-states}

<div class=informative-bg>
<em>This section is non-normative</em>

  At a given moment,
  an [=animation effect=] can be in one of three possible <em>phases</em>.
  If an [=animation effect=] has an [=unresolved=] [=local time=]
  it will not be in any phase.

  The different phases are illustrated below.

  <figure>
    <img src="images/animation-effect-phases-and-states.svg" width="700"
        alt="An example of the different phases and states
             used to describe an animation effect.">
    <figcaption>
      An example of the different phases and states
      used to describe an [=animation effect=].
    </figcaption>
  </figure>

  The phases are as follows:

  : [=animation effect/before phase=]
  ::
      The [=animation effect=]’s [=local time=]
      falls before
      the effect's [=active interval=] and [=animation effect/end time=],
      <em>or</em>
      occurs during the range when a negative [=start delay=] is in effect.

  : [=animation effect/active phase=]
  ::
      The [=animation effect=]’s [=local time=] falls
      inside the effect's [=active interval=]
      and outside the range of any negative [=start delay=]
      or negative [=end delay=].

  : [=animation effect/after phase=]
  ::
      The [=animation effect=]’s [=local time=] falls
      after the effect's [=active interval=]
      or after the [=animation effect/end time=] if that comes first
      (due to a negative [=end delay=]),
      but <em>not</em> during the range when a negative [=start delay=]
      is in effect.

  In addition to these phases,
  an [=animation effect=] can also be described as being
  in one of several overlapping <em>states</em>.
  These states are only established
  for the duration of a single [=animation frame=]
  and are primarily a convenience for describing stative parts of the model.

  These states and their usage within the model
  are summarized as follows:

  : [=in play=]
  ::
      Corresponds to an [=animation effect=]
      whose [=active time=] is changing on each frame.

  : [=current=]
  ::
      Corresponds to an [=animation effect=]
      that is either [=in play=] or
      could become [=in play=] in the future
      based on its [=animation=]'s current [=playback rate=].

  : [=in effect=]
  ::
      Corresponds to an [=animation effect=]
      that has a resolved [=active time=].
      This occurs when either the [=animation effect=]
      is in its [=animation effect/active phase=]
      or outside the [=animation effect/active phase=]
      but at a time where the effect's [=fill mode=]
      (see [[#fill-behavior]])
      causes its [=active time=] to be resolved.
      Only [=in effect=] [=animation effects=]
      apply a result to their target.

  The normative definition of each of these states follows.

</div>

  The phase of an [=animation effect=]
  depends on the following definitions:

  : <dfn>animation direction</dfn>
  ::
      “backwards” if the effect is [=associated with an animation=] <em>and</em>
      the associated [=animation=]’s [=playback rate=] is less than zero;
      in all other cases, the [=animation direction=] is “forward”.

  : <dfn>before-active boundary time</dfn>
  ::
      <code>max(min(<a>start delay</a>,
                    <a for="animation effect">end time</a>), 0)</code>

  : <dfn>active-after boundary time</dfn>
  ::
      <code>max(min(<a>start delay</a> + <a>active duration</a>,
                    <a for="animation effect">end time</a>), 0)</code>


  Furthermore, an <dfn>endpoint-inclusive active interval</dfn> flag
  may be specified when determining the phase.
  If not specified, it is assumed to be false.

  An [=animation effect=] is in the
  <dfn export for="animation effect">before phase</dfn>
  if the animation effect's [=local time=]
  is not [=unresolved=] and
  <em>either</em> of the following conditions are met:

  * the [=local time=] is less than the [=before-active boundary time=],
      <em>or</em>
  * the [=animation direction=] is “backwards”,
      the [=endpoint-inclusive active interval=] flag is false,
      and the [=local time=] is equal to the [=before-active boundary time=].

  An [=animation effect=] is in the
  <dfn export for="animation effect">after phase</dfn>
  if the animation effect's [=local time=]
  is not [=unresolved=] and
  <em>either</em> of the following conditions are met:

  * the [=local time=] is greater than the [=active-after boundary time=],
      <em>or</em>
  * the [=animation direction=] is “forwards”,
      the [=endpoint-inclusive active interval=] flag is false,
      and the [=local time=] is equal to the [=active-after boundary time=].

  An [=animation effect=] is in the
  <dfn export for="animation effect">active phase</dfn>
  if the animation effect's [=local time=] is not [=unresolved=]
  and it is neither in the [=animation effect/before phase=]
  nor in the [=animation effect/after phase=].

  Furthermore,
  it is often convenient to refer to the case when an animation effect
  is in none of the above phases
  as being in the <dfn export for="animation effect">idle phase</dfn>.

  An [=animation effect=] is <dfn>in play</dfn>
  if <em>all</em> of the following conditions are met:

  * the [=animation effect=] is in the [=animation effect/active phase=], and
  * the [=animation effect=] is [=associated with an animation=]
      that is not [=play state/finished=].

  An [=animation effect=] is <dfn>current</dfn>
  if <em>any</em> of the following conditions are true:

  * the [=animation effect=] is
      [=in play=],
      or
  * the [=animation effect=] is
      in the [=animation effect/before phase=]
      and is [=associated with an animation=] with a [=playback rate=] > 0,
      or
  * the [=animation effect=] is
      in the [=animation effect/after phase=]
      and is [=associated with an animation=] with a [=playback rate=] < 0,
      or
  * the [=animation effect=] is
      [=associated with an animation=]
      not in the [=play state/idle=] [=play state=]
      with a non-null associated [=timeline=]
      that is not [=monotonically increasing=].

  An animation effect is <dfn>in effect</dfn>
  if its [=active time=],
  as calculated according to the procedure in [[#calculating-the-active-time]],
  is <em>not</em> [=unresolved=].

### Relevant animations ### {#relevant-animations-section}

  We can define an [=animation=] as being [=relevant=]
  based on the [=animation effect=] [=associated effect|associated=] with it.

  An [=animation=] is <dfn for=animation export>relevant</dfn> if:

  * Its [=associated effect=] is [=current=] <em>or</em> [=in effect=],
      <em>and</em>
  * Its [=replace state=] is <em>not</em> [=removed replace state|removed=].

  <div algorithm="get relevant animations">

    The <dfn export>relevant animations</dfn>
    for an element or pseudo-element |target|
    is the set of all [=animations=] that contain
    at least one [=animation effect=]
    whose [=effect target=] is |target|.

  </div>

  <div algorithm="get relevant animations for a subtree">

    The <dfn export>relevant animations for a subtree</dfn>
    of an element, pseudo-element, [=document=], or [=shadow root=] |target|
    is the set of all [=animations=]
    that contain at least one [=animation effect=]
    whose [=effect target=] is an [=inclusive descendant=]
    (or [=descendant=], if |target| is a [=document=] or [=shadow root=])
    of |target|
    or is a [=pseudo-element=] of such a descendant.

  </div>


### Fill behavior and fill modes ### {#fill-behavior}

  The effect of an [=animation effect=] when it is not [=in play=]
  is determined by its <dfn>fill mode</dfn>.
  The effect of each [=fill mode=] is described below:

  <dl dfn-for="fill mode" id="fill-modes">
  : <dfn>none</dfn>
  ::
      The animation effect has no effect when it is not [=in play=].

  : <dfn>forwards</dfn>
  ::
      When the animation effect is in the [=animation effect/after phase=],
      the animation effect will produce the same [=iteration progress=] value
      as the last moment it is scheduled to be [=in play=].

      For all other times that the animation effect is not [=in play=],
      it will have no effect.

  : <dfn>backwards</dfn>
  ::
      When the animation effect is in the [=animation effect/before phase=],
      the animation effect will produce the same [=iteration progress=] value
      as the earliest moment that it is scheduled to be [=in play=].

      For all other times that the animation effect is not [=in play=],
      it will have no effect.

  : <dfn>both</dfn>
  ::
      When the animation effect is in its [=animation effect/before phase=],
      [=fill mode/backwards=] fill behavior is used.

      When the animation effect is in its [=animation effect/after phase=],
      [=fill mode/forwards=] fill behavior is used.

  </dl>

  The normative effect of these modes
  is incorporated in the calculation of the [=active time=]
  in [[#calculating-the-active-time]].

  Some examples of these [=fill modes=] are illustrated below.

  <figure>
    <img src="images/animation-state-and-fill-behavior.svg" width="600"
         alt="Examples of various fill modes and the states produced.">
    <figcaption>
      Examples of various fill modes and the states produced.<br>
      (a) fill mode [=fill mode/none=].
          The animation effect has no effect outside its active phase.<br>
      (b) fill mode [=fill mode/forwards=].
          After the active phase has finished,
          the [=iteration progress=] value continues to maintain a fill value.<br>
      (c) fill mode [=fill mode/backwards=].
          The animation effect produces a fill value
          until the start of the active phase.<br>
      (d) fill mode [=fill mode/both=].
          Both before and after the active phase
          the animation effect produces a fill value.
    </figcaption>
  </figure>

  Note:
    Authors are discouraged from using [=fill modes=]
    to produce animations whose effect is applied indefinitely.
    [=Fill modes=] were introduced
    in order to represent the 'animation-fill-mode' property
    defined by CSS animations [[CSS-ANIMATIONS-1]].
    However, they produce situations where animation state
    would be accumulated indefinitely,
    necessitating the automatic removal of animations
    (as defined in [[#replacing-animations]]).
    Furthermore, indefinitely filling animations
    can cause changes to specified styles to be ineffective
    long after all animations have completed
    since the animation style takes precedence in the CSS cascade.
    [[CSS-CASCADE-3]]

  <strong class=advisement>
    Where possible, authors should set
    the final state of the animation directly in specified styles.
  </strong>

  <div class=example>
    This can be achieved by waiting for the animation to finish
    and then updating the style as illustrated below:

    <pre highlight=javascript>
      // In the first frame after the following animation finishes,
      // the callback for the \`finished\` promise will run
      // BEFORE style is updated, and hence will NOT flicker.
      elem.animate({ transform: 'translateY(100px)' }, 200).finished.then(() => {
        elem.style.transform = 'translateY(100px)';
      });
    </pre>
  </div>

  <div class=example>
    More conveniently, an {{Animation}}'s {{Animation/commitStyles}} method can
    be used to produce the same effect.

    <pre highlight=javascript>
      elem.animate({ transform: 'translateY(100px)' }, 200).finished.then(() => {
        elem.commitStyles();
      });
    </pre>
  </div>

  <div class=example>
    Alternatively, the author can set the specified style
    at the start of the animation and then animate <em>from</em>
    the original value as illustrated below:

    <pre highlight=javascript>
      elem.style.transform = 'translateY(100px)';
      elem.animate({ transform: 'none', offset: 0 }, 200);
    </pre>
  </div>

  Note: Setting a [=fill mode=] has no bearing on
  the endpoints of the [=active interval=]
  or the boundaries between [[#animation-effect-phases-and-states|phases]]
  However, the fill mode <em>does</em> have an effect
  on various other properties of the timing model
  since the [=active time=] of an animation effect
  is only defined (that is, not [=unresolved=])
  inside the [=animation effect/active phase=]
  <em>or</em> when a fill is applied.

### Repeating ### {#repeating}

#### Iteration intervals #### {#iteration-intervals}

  It is possible to specify that an animation effect should repeat
  a fixed number of times or indefinitely.
  This repetition occurs <em>within</em> the [=active interval=].
  The span of time during which a single repetition takes place
  is called an <dfn>iteration interval</dfn>.

  Unlike the [=active interval=],
  an animation effect can have multiple [=iteration intervals=],
  although typically only the interval corresponding
  to the current iteration
  is of interest.

  The length of a single iteration is called
  the <dfn>iteration duration</dfn>.
  The initial [=iteration duration=] of an animation effect is zero.

<div class=informative-bg>
<em>This section is non-normative</em>

  Comparing the [=iteration duration=] and the [=active duration=]
  we have:

  : iteration duration
  ::
      The time taken for a single iteration of the animation effect
      to complete.

  : active duration
  ::
      The time taken for the entire animation effect to complete,
      including repetitions.
      This can be longer or shorter than the [=iteration duration=].

  The relationship between the [=iteration duration=] and [=active duration=]
  is illustrated below.

  <figure>
    <img src="images/iteration-intervals.svg" width="600"
         alt="Comparison of the iteration duration and active time.">
    <figcaption>
      A comparison of the [=iteration duration=] and [=active duration=]
      of an animation effect with an [=iteration count=] of 2.5.
      Note that the [=iteration duration=] for the final iteration
      does not change; it is simply cut-off by the [=active duration=].
    </figcaption>
  </figure>
</div>

#### Controlling iteration #### {#controlling-iteration}

  The number of times an [=animation effect=] repeats
  is called its <dfn>iteration count</dfn>.
  The [=iteration count=] is a real number greater than or equal to zero.
  The [=iteration count=] can also be positive infinity
  to represent that the [=animation effect=] repeats indefinitely.

  In addition to the [=iteration count=],
  [=animation effects=] also have an <dfn>iteration start</dfn> property
  which specifies an offset into the series of iterations
  at which the [=animation effect=] should begin.
  The [=iteration start=] is a finite real number
  greater than or equal to zero.

  The behavior of these parameters is defined
  in the calculations in [[#core-animation-effect-calculations]].

<div class=informative-bg>
<em>This section is non-normative</em>

  The effect of the [=iteration count=] and [=iteration start=] parameters
  is illustrated below.

  <figure>
    <img src="images/iteration-count-and-start.svg" width="600"
      alt="The effect of the iteration count and iteration start parameters">
    <figcaption>
      The effect of the [=iteration count=] and [=iteration start=]
      parameters.<br>
      In the first case the [=iteration count=] is 2.5
      resulting in the third iteration being cut off
      halfway through its [=iteration interval=].<br>
      The second case is the same
      but with an [=iteration start=] of 0.5.
      This causes the [=animation effect=] to begin
      halfway through the first iteration.
    </figcaption>
  </figure>

  Unlike the [=iteration count=] parameter, the [=iteration start=] parameter
  does not affect the length of the [=active duration=].

  Note that values of [=iteration start=] greater than or equal to one
  are generally not useful
  unless used in combination with an [=animation effect=]
  that has an [=iteration composite operation=]
  of [=iteration composite operation accumulate|accumulate=].

</div>

#### Interval timing #### {#interval-timing}

<div class=informative-bg>
<em>This section is non-normative</em>

  When an animation effect repeats,
  the behavior at the iteration boundaries needs to be defined.
  For this, and indeed for all interval timing,
  Web Animations uses an endpoint-exclusive timing model.
  This means that whilst the begin time of an interval
  is included in the interval, the end time is not.
  In interval notation this can written <code>[begin, end)</code>.
  This model provides sensible behavior
  when intervals are repeated and sequenced
  since there is no overlap between the intervals.

  In the examples below, for the repeated effect, at local time 1s,
  the iteration time is 0.
  For the sequenced animations, at timeline time 1s,
  only animation B's [=associated effect=] will be [=in play=];
  there is no overlap.

  <figure>
    <img src="images/endpoint-exclusive-timing.svg" width="600"
        alt="Illustration of end-point exclusive timing.">
    <figcaption>
      Illustration of end-point exclusive timing.
      For both repeated and sequenced animation effects
      there is no overlap at the boundaries between intervals.
    </figcaption>
  </figure>

  An exception to this behavior is that
  when performing a [[#fill-behavior|fill]],
  if the fill begins at an interval endpoint,
  the endpoint is used.
  This behavior falls out of the algorithm given in
  [[#calculating-the-simple-iteration-progress]]
  and is illustrated below.

  <figure>
    <img src="images/endpoint-exclusive-timing-and-fill.svg" width="600"
         alt="Effect of iterations and fill on iteration time.">
    <figcaption>
      After one iteration, the [=iteration progress=] is 0,
      but after two iterations (and there onwards),
      the [=iteration progress=] is 1
      due to the special behavior defined when an animation effect fills.
    </figcaption>
  </figure>

</div>

### Direction control ### {#direction-control}

  [=Animation effects=] can also be configured
  to run iterations in alternative directions
  using direction control.
  For this purpose, [=animation effects=] have
  a <dfn>playback direction</dfn> parameter
  which takes one of the following values:

  <dl dfn-for="playback direction">

  : <dfn>normal</dfn>
  ::
      All iterations are played as specified.

  : <dfn>reverse</dfn>
  ::
      All iterations are played in the reverse direction
      from the way they are specified.

  : <dfn>alternate</dfn>
  ::
      Even iterations are played as specified;
      odd iterations are played in the reverse direction
      from the way they are specified.

  : <dfn>alternate-reverse</dfn>
  ::
      Even iterations are played in the reverse direction
      from the way they are specified;
      odd iterations are played as specified.

  </dl>

  The semantics of these values are incorporated into
  the calculation of the [=directed progress=]
  in [[#calculating-the-directed-progress]].

### Easing (effect timing transformations) ### {#time-transformations}

  It is often desirable to control the rate
  at which an [=animation effect=] progresses.
  For example, easing the rate of animation
  can create a sense of momentum and produce a more natural effect.
  The <a href="https://www.w3.org/TR/css-easing/">CSS Easing Functions Module</a>
  defines [=easing functions=] for this purpose.
  [[!CSS-EASING-1]]

  [=Animation effects=] each have
  an <dfn for="animation effect">effect easing function</dfn>,
  which is an [=easing function=]
  used to transform progress across the entirety of each iteration.
  See [[#calculating-the-transformed-progress]].

  The default [=effect easing function=]
  is the [=linear easing function=].

  Note: Specific [[#types-of-animation-effects|types of animation effects]]
  may provide additional time transformations.
  For example, [=keyframe effects=] can provide
  [=keyframe-specific easing functions=]
  that can apply an [=easing function=]
  specifically between two adjacent keyframes.

Calculating progress {#core-animation-effect-calculations}
--------------------

### Overview ### {#animation-effect-calculations-overview}

<div class=informative-bg>
<em>This section is non-normative</em>

  At the core of the Web Animations timing model
  is the process that takes a [=local time=] value
  and converts it to an [=iteration progress=].

  The first step in this process is to calculate
  the bounds of the [=active interval=]
  which is determined by the [=active duration=].

  This process is illustrated below.

  <figure>
    <img src="images/active-duration-calculation.svg" width="650"
         alt="Calculation of the active duration.">
    <figcaption>
      Calculation of the [=active duration=]
      is based on multiplying the [=iteration duration=]
      by the [=iteration count=].
    </figcaption>
  </figure>

  Having established the [=active duration=],
  the process for transforming an [=animation effect=]’s [=local time=]
  into its [=transformed progress=] ([=iteration progress=])
  is illustrated below.

  <figure>
    <img src="images/time-calculations.svg" width="650"
         alt="An overview of timing model calculations.">
    <figcaption>
      An overview of timing model calculations.<br>
      (1) The [=local time=] is determined from the associated [=animation=].<br>
      (2) The [=local time=] is converted into an [=active time=]
          by incorporating the [=start delay=].<br>
      (3) The [=active time=] is divided by the [=iteration duration=]
          incorporating also the [=iteration start=] property
          to produce the [=overall progress=].<br>
      (4) The [=overall progress=] time is then converted
          to an offset within a single iteration:
          the [=simple iteration progress=].<br>
      (5) The [=simple iteration progress=] is converted
          into a [=directed progress=]
          by incorporating the [=playback direction=].<br>
      (6) Finally, an [=easing function=] is applied to the [=directed progress=]
          to produce the [=transformed progress=].
    </figcaption>
  </figure>

  The first step, calculating the [=local time=]
  is described in [[#local-time-section]].
  Steps 2 to 6 in the diagram are described in the following sections.

</div>

### Calculating the active time ### {#calculating-the-active-time}

  The <dfn>active time</dfn> is based on the [=local time=] and [=start delay=].
  However, it is only defined
  when the [=animation effect=] should produce an output
  and hence depends on its [=fill mode=] and phase as follows:

  <dl class=switch>

  : If the animation effect is in the [=animation effect/before phase=],
  ::  The result depends on the first matching condition from the following:

      <dl class=switch>

      : If the [=fill mode=] is
          [=fill mode/backwards=] or [=fill mode/both=],
      ::
          Return the result of evaluating
          <code>max(<a>local time</a> − <a>start delay</a>, 0)</code>.

      : Otherwise,
      ::
          Return an [=unresolved=] [=time value=].

      </dl>

  : If the animation effect is in the [=animation effect/active phase=],
  ::
      Return the result of evaluating
      <code><a>local time</a> − <a>start delay</a></code>.

  : If the animation effect is in the [=animation effect/after phase=],
  ::  The result depends on the first matching condition from the following:

      <div class=switch>

      : If the [=fill mode=] is
          [=fill mode/forwards=] or [=fill mode/both=],
      ::
          Return the result of evaluating
          <code>max(min(<a>local time</a> − <a>start delay</a>,
                        <a>active duration</a>),
                    0)</code>.
      : Otherwise,
      ::
          Return an [=unresolved=] [=time value=].

      </div>

  : Otherwise (the [=local time=] is [=unresolved=]),
  ::
      Return an [=unresolved=] [=time value=].

  </dl>

### Calculating the overall progress ### {#calculating-the-overall-progress}

  The <dfn>overall progress</dfn> describes
  the number of iterations that have completed (including partial iterations)
  and is defined as follows:

  1. If the [=active time=] is [=unresolved=],
      return [=unresolved=].

  1. Calculate an initial value for |overall progress|
      based on the first matching condition below:

      <div class=switch>

      : If the [=iteration duration=] is zero,
      ::
          If the animation effect is in the [=animation effect/before phase=],
          let |overall progress| be zero;
          otherwise, let it be equal to the [=iteration count=].

      : Otherwise,
      ::
          Let |overall progress| be the result of calculating
          <code><a>active time</a> / <a>iteration duration</a></code>.

      </div>

  1. Return the result of calculating
      <code><var>overall progress</var> + <a>iteration start</a></code>.

  <wpt>
    interfaces/Animation/overallProgress.html
  </wpt>


### Calculating the simple iteration progress ### {#calculating-the-simple-iteration-progress}

  The <dfn>simple iteration progress</dfn>
  is a fraction of the progress through the current iteration
  that ignores transformations to the time introduced by
  the [=playback direction=] or [=easing functions=] applied to the effect,
  and is calculated as follows:

  1. If the [=overall progress=] is [=unresolved=],
      return [=unresolved=].

  1. If [=overall progress=] is infinity,
      let the |simple iteration progress| be
      <code><a>iteration start</a> % 1.0</code>;
      otherwise,
      let the |simple iteration progress| be
      <code><a>overall progress</a> % 1.0</code>.

  1. If <em>all</em> of the following conditions are true:

      * the |simple iteration progress| calculated above is zero,
          <em>and</em>
      * the animation effect is in the [=animation effect/active phase=]
          <em>or</em> the [=animation effect/after phase=],
          <em>and</em>
      * the [=active time=] is equal to the [=active duration=],
          <em>and</em>
      * the [=iteration count=] is <em>not</em> equal to zero.

      Let the |simple iteration progress| be 1.0.

      <div class=note>

        The above step implements the behavior that
        when an animation's active interval ends
        precisely at the end of an iteration,
        it fills by holding the endpoint of the final iteration
        rather than the start of the next iteration.

        The final condition prevents this from applying
        when we never played any iterations of the animation to begin with
        because the [=iteration count=] was zero.

      </div>

  1. Return |simple iteration progress|.


### Calculating the [=current iteration index=] ### {#calculating-the-current-iteration}

  The <dfn lt="current iteration index | iteration index">current iteration index</dfn>
  can be calculated
  using the following steps:

  1. If the [=active time=] is [=unresolved=],
      return [=unresolved=].

  1. If the animation effect is in the [=animation effect/after phase=] <em>and</em>
      the [=iteration count=] is infinity,
      return infinity.

  1. If the [=simple iteration progress=] is 1.0,
      return <code>floor(<a>overall progress</a>) − 1</code>.

  1. Otherwise, return <code>floor(<a>overall progress</a>)</code>.

### Calculating the directed progress ### {#calculating-the-directed-progress}

  The <dfn>directed progress</dfn> is calculated
  from the [=simple iteration progress=]
  using the following steps:

  1. If the [=simple iteration progress=] is [=unresolved=],
      return [=unresolved=].

  1. Calculate the |current direction|
      using the first matching condition from the following list:

      <dl class=switch>

      : If [=playback direction=] is [=playback direction/normal=],
      ::
          Let the |current direction| be forwards.

      : If [=playback direction=] is [=playback direction/reverse=],
      ::
          Let the |current direction| be reverse.

      : Otherwise
          (the [=playback direction=] is
          [=playback direction/alternate=] or [=playback direction/alternate-reverse=])p,
      ::
          1. Let |d| be the [=current iteration index=].

          1. If [=playback direction=] is [=playback direction/alternate-reverse=]
              increment |d| by 1.

          1. If <code><var>d</var> % 2 == 0</code>,
              let the |current direction| be forwards;
              otherwise let the |current direction| be reverse.
              If |d| is infinity,
              let the |current direction| be forwards.

      </dl>

  1. If the |current direction| is forwards
      then return the [=simple iteration progress=].

      Otherwise, return
      <code>1.0 − <a>simple iteration progress</a></code>.

### Calculating the transformed progress ### {#calculating-the-transformed-progress}

  The <dfn export>transformed progress</dfn> is calculated
  from the [=directed progress=] using the following steps:

  1. If the [=directed progress=] is [=unresolved=],
      return [=unresolved=].

  1. Calculate the value of the |before flag| as follows:

      1. Determine the |current direction| using
          the procedure defined in [[#calculating-the-directed-progress]].
      1. If the |current direction| is <span class="prop-value">forwards</span>,
          let |going forwards| be true; otherwise it is false.
      1. The |before flag| is set
          if the animation effect is in the [=animation effect/before phase=]
          and |going forwards| is true;
          or if the animation effect is in the [=animation effect/after phase=]
          and <var>going forwards</var> is false.

  1. Return the result of evaluating
      the [=effect easing function=]
      passing [=directed progress=] as the <a spec=css-easing>input progress value</a>
      and |before flag| as the <a spec=css-easing>before flag</a>.

### Yielding the iteration progress ### {#the-iteration-progress}

  The final output <dfn>iteration progress</dfn> of an [=animation effect=]
  is simply its [=transformed progress=].


<!-- End of timing model -->

<!--
     ███    ██    ██ ████ ██     ██    ███    ████████ ████  ███████  ██    ██
    ██ ██   ███   ██  ██  ███   ███   ██ ██      ██     ██  ██     ██ ███   ██
   ██   ██  ████  ██  ██  ████ ████  ██   ██     ██     ██  ██     ██ ████  ██
  ██     ██ ██ ██ ██  ██  ██ ███ ██ ██     ██    ██     ██  ██     ██ ██ ██ ██
  █████████ ██  ████  ██  ██     ██ █████████    ██     ██  ██     ██ ██  ████
  ██     ██ ██   ███  ██  ██     ██ ██     ██    ██     ██  ██     ██ ██   ███
  ██     ██ ██    ██ ████ ██     ██ ██     ██    ██    ████  ███████  ██    ██
-->

Animation model {#animation-model}
===============

<div class=informative-bg>
<em>This section is non-normative</em>

  For some kinds of [=animation effects=],
  the <dfn>Web Animations [=animation model=]</dfn>
  takes the [=iteration progress=] and [=iteration index=] values
  produced by the [=Web Animations timing model|timing model=]
  and uses them to calculate a corresponding output.

  The output of each such animation effect
  is then combined with that of others using an [=effect stack=]
  before being applied to the [=target properties=]
  (see [[#combining-effects]]).

</div>

Introduction {#introduction-to-the-animation-model}
------------

  An [=animation effect=] has zero or more associated properties
  that it affects in response to changes to its timing output.
  These properties are referred to as the effect's
  <dfn lt="target property">target properties</dfn>.

  Given an [=iteration progress=],
  an [=iteration index=],
  and an [=underlying value=],
  an [=animation effect=] produces an <dfn>effect value</dfn>
  for each [=animatable=] [=target property=]
  by applying the procedures from the [=animation type=]
  appropriate to the property.

Animating properties {#animating-properties}
--------------------

  Unless otherwise specified, all CSS properties are
  <dfn id="concept-animatable">animatable</dfn>.
  How property values combine is defined by
  the <dfn export>Animation type</dfn> line
  in each property's property definition table:

  <dl export>
  : <dfn>not animatable</dfn>
  ::
      The property is not animatable.
      It is not processed when listed in an animation keyframe,
      and is not affected by transitions.

      Note: Properties are typically excluded from animation
      because animating them would create excessive complications.
      For example, properties defining animation parameters
      are [=not animatable=]
      since doing so would create complex recursive behavior.

      Note: An [=animation effect=] that targets
      only properties that are [=not animatable=]
      will still exhibit the usual behavior for an [=animation effect=]
      such as firing events and delaying the fulfillment
      of the [=animation=]’s [=current finished promise=].

  : <dfn>discrete</dfn>
  ::
      The property's values cannot be meaningfully combined,
      thus it is [=not additive=].
      [=Interpolation=] swaps
      from <var ignore>V<sub>a</sub></var> to <var ignore>V<sub>b</sub></var>
      at 50% (<var ignore>p=0.5</var>),
      i.e.
      <div role="math" class=formula>
        <math xmlns="http://www.w3.org/1998/Math/MathML">
          <msub><mi>V</mi><mn>result</mn></msub><mo>=</mo>
          <mrow>
            <mfenced open="{" close="">
              <mtable>
                <mtr>
                  <mtd columnalign="left">
                    <msub><mi>V</mi><mn>start</mn></msub>
                  </mtd>
                  <mtd columnalign="left">
                    <mtext>if&nbsp;</mtext><mi>p</mi>
                    <mo>&lt;</mo><mn>0.5</mn>
                  </mtd>
                </mtr>
                <mtr>
                  <mtd columnalign="left">
                    <msub><mi>V</mi><mn>end</mn></msub>
                  </mtd>
                  <mtd columnalign="left">
                    <mtext>if&nbsp;</mtext><mi>p</mi>
                    <mo>&ge;</mo><mn>0.5</mn>
                  </mtd>
                </mtr>
              </mtable>
            </mfenced>
          </mrow>
        </math>
      </div>

  : <dfn>by computed value</dfn>
  ::
      Corresponding individual components of the [=computed values=]
      are combined (interpolated, added, or accumulated)
      using the indicated procedure for that value type
      (see [[css-values-4#combining-values]]).
      If the number of components or the types of corresponding components
      do not match,
      or if any component value uses [=discrete=] animation
      and the two corresponding values do not match,
      then the property values combine as [=discrete=].

    <dt><dfn>repeatable list</dfn>
    <dd>
      Same as [=by computed value=]
      except that if the two lists have differing numbers of items,
      they are first repeated to the least common multiple number of items.
      Each item is then combined [=by computed value=].
      If a pair of values cannot be combined
      or if any component value uses [=discrete=] animation,
      then the property values combine as [=discrete=].

      Note: The repeatable list concept ensures that
      a list that is conceptually repeated to a certain length
      (as 'background-origin' is repeated to the length of
      the 'background-image' list)
      or repeated infinitely
      will smoothly transition between any values,
      and so that the computed value
      will properly represent the result
      (and potentially be inherited correctly).

    <dt>(See prose)
    <dd>
      Some properties have specific interpolation behavior
      not covered by the above cases;
      in this case the animation behavior will be specified explicitly
      for that property.

  </dl>

  The [=animation type=] of properties that do not yet include
  an [=Animation type=] line in their property definition,
  is defined in [[#animation-types]].

### Custom Properties ### {#custom-properties}

  For [=custom properties=] registered using
  the {{CSS/registerProperty()}} method for the [=current global object=],
  the [=animation type=] is [=by computed value=],
  derived from the type used in the property's [=syntax definition=].
  Where there is no [=computed value=] type that corresponds
  to the property's specified syntax
  (e.g. when the syntax is the [=universal syntax definition=])
  or when the [=custom property=] is not registered,
  the [=animation type=] is [=discrete=].

Keyframe effects {#keyframe-effects}
----------------

  <dfn lt="keyframe effect">Keyframe effects</dfn>
  are a kind of [=animation effect=]
  that uses the output of the timing model
  to update CSS properties of an element
  or [=pseudo-element=] (such as `::before` or `::after` [[!select]])
  referred to as the <dfn for="keyframe effect" export>effect target</dfn>.

  The [=effect target=] is comprised of
  an {{Element}} known as the <dfn for="effect target" export>target element</dfn>
  and a [=pseudo-element=] selector known as the
  <dfn for="effect target" export>target pseudo-selector</dfn>.
  If the [=effect target=] is an {{Element}},
  the [=target element=] is that element
  and the [=target pseudo-selector=] is null.
  If the [=effect target=] is a [=pseudo-element=],
  the [=target element=] is its [=originating element=]
  and the [=target pseudo-selector=] is one that specifies
  that particular [=pseudo-element=].

  Note that not all [=effect targets=] specified in this manner
  (such as ''::part()'' pseudo-elements and unsupported pseudo-elements)
  have computed property values defined.

### Keyframes ### {#keyframes-section}

  The [=effect values=] for a [=keyframe effect=]
  are calculated by interpolating between
  a series of property values positioned at fractional offsets.
  Each set of property values indexed by an offset
  is called a <dfn>keyframe</dfn>.

  The <dfn lt="keyframe offset">offset of a keyframe</dfn> is
  a value in the range [0, 1] or the special value null.
  The list of [=keyframes=] for a [=keyframe effect=]
  must be <dfn>loosely sorted by offset</dfn>,
  which means that for each [=keyframe=] in the list
  that has a [=keyframe offset=] that is not null,
  the offset must be greater than or equal to
  the offset of the previous [=keyframe=] in the list
  with a [=keyframe offset=] that is not null, if any.

  The behavior when [=keyframes=] overlap
  or have unsupported values is defined in
  [[#the-effect-value-of-a-keyframe-animation-effect]].

  Each keyframe also has a <dfn>keyframe-specific easing function</dfn>
  associated with it, which is an [=easing function=]
  that is applied to the period of time between
  the keyframe on which it is specified
  and the <em>next</em> keyframe in the list.

  Note: The [=easing function=] specified on the last keyframe in the list
  is never applied.

  Each [=keyframe=] may have a <dfn>keyframe-specific composite operation</dfn>
  that, if set, is applied to all values specified in that [=keyframe=].
  The possible operations and their meanings
  are identical to those defined for the [=composite operation=]
  associated with the [=keyframe effect=] as a whole in [[#effect-composition]].
  If the [=keyframe-specific composite operation=] for a [=keyframe=]
  is not set,
  the [=composite operation=] specified for the [=keyframe effect=] as a whole
  is used for values specified in that keyframe.

  <wpt>
    animation-model/combining-effects/applying-interpolated-transform.html
  </wpt>

### Computing property values ### {#computing-property-values}

  <div algorithm>
    To <dfn>compute a property value</dfn> given a property |property|,
    a value |value|,
    and an {{Element}} |element|:
    resolve |value| according to the “Computed Value” line
    of the |property|'s definition table,
    using the [=computed values=] of |element|
    as the context for resolving dependencies,
    and return the result.

    Note: The [=computed values=] on |element|
    are not affected by this algorithm.

    This algorithm implies that property values specified in keyframes
    can establish order dependencies.
    When [=compute a property value|computing a property value=],
    the [=computed values=] of dependencies held by |value|
    must be calculated <em>first</em>.

    <div class=example>
      <pre highlight=javascript>
        var animation = elem.animate([{ fontSize: '10px', width: '10em' },
                                      { fontSize: '20px', width: '20em' }], 1000);
        animation.currentTime = 500;
        console.log(getComputedStyle(elem).fontSize); // Should be 15px
        console.log(getComputedStyle(elem).width); // Should be 225px
      </pre>

      In this example,
      in order to [=compute a property value=] for <code>10em</code>,
      we need to know the [=computed value=] of 'font-size' on the [=target element=],
      which in turn is determined by the [=effect value=] for 'font-size',
      which in turn depends on computing property values for 'font-size'.
      Hence, computing property values are subject to ordering constraints.
    </div>

  </div>

### Calculating computed keyframes ### {#calculating-computed-keyframes}

  Before calculating the [=effect value=] of a [=keyframe effect=],
  the property values on its [=keyframes=] are
  [[#computing-property-values|computed]],
  and the offset to use for any keyframes with a null [=keyframe offset=]
  is computed.
  The result of resolving these values
  is a set of <dfn>computed keyframes</dfn>.

  The calculated [=keyframe offsets=]
  of a set of [=keyframe=] that includes suitable values
  for each null [=keyframe offset=]
  are referred to as the
  <dfn>computed keyframe offsets</dfn>.

  <div algorithm="compute missing keyframe offsets">
    To produce [=computed keyframe offsets=],
    we define a procedure to <dfn>compute missing keyframe offsets</dfn>
    that takes a sequence of [=keyframes=], |keyframes|,
    and has the following steps:

    1. For each [=keyframe=] in |keyframes|,
        let the [=computed keyframe offset=] of the [=keyframe=]
        be equal to its [=keyframe offset=] value.

    1. If |keyframes| contains more than one [=keyframe=]
        and the [=computed keyframe offset=]
        of the first [=keyframe=] in |keyframes|
        is null,
        set the [=computed keyframe offset=] of the first [=keyframe=]
        to 0.

    1. If the [=computed keyframe offset=]
        of the last [=keyframe=] in |keyframes|
        is null,
        set its [=computed keyframe offset=] to 1.

    1. For each pair of [=keyframes=] |A| and |B|
        where:

        * |A| appears before |B| in |keyframes|, and
        * |A| and |B| have a [=computed keyframe offset=]
            that is not null, and
        * all [=keyframes=] between |A| and |B|
            have a null [=computed keyframe offset=],

        calculate the [=computed keyframe offset=]
        of each [=keyframe=] between |A| and |B|
        as follows:

        1. Let <dfn>offset<sub>|k|</sub></dfn> be
            the [=computed keyframe offset=] of a [=keyframe=] |k|.
        1. Let |n| be
            the number of keyframes <em>between</em> and including
            |A| and |B| minus 1.
        1. Let |index| refer to the position
            of |keyframe| in the sequence of keyframes between |A| and |B|
            such that the first keyframe after |A| has an |index| of 1.
        1. Set the [=computed keyframe offset=] of |keyframe| to
            [=offsetk|offset=]<sub>|A|</sub> +
            ([=offsetk|offset=]<sub>|B|</sub> &minus;
            [=offsetk|offset=]<sub>|A|</sub>)
            × |index| / |n|.
  </div>

  <wpt>
    animation-model/keyframe-effects/background-shorthand.html
    animation-model/keyframe-effects/computed-keyframes-shorthands.html
    animation-model/keyframe-effects/effect-value-context-filling.html
    animation-model/keyframe-effects/effect-value-context.html
  </wpt>

  [=Computed keyframes=] are produced using the following procedure.
  Note that this procedure is only performed
  on a [=keyframe effect=] having an [=effect target=]
  for which computed property values can be calculated.

  1. Let |computed keyframes| be an empty list of [=keyframes=].

  1. For each |keyframe| in the list of [=keyframes=]
      specified on this [=keyframe effect=],
      perform the following steps:

      1. Add a new empty [=keyframe=], |computed keyframe|,
          to |computed keyframes|.

      1. For each property specified in |keyframe|:
          * [=Compute a property value=]
              using the value specified on |keyframe| as the value,
              and the [=target element=] as the element;
              then add the property and resulting value to |computed keyframe|.
          * For shorthand properties, add the equivalent longhand properties.
          * For logical properties [[!CSS-LOGICAL-1]],
              add the [=equivalent physical properties=] [[!CSS-WRITING-MODES-4]]
              based on the computed value of 'writing-mode' and/or 'direction'
              for the [=effect target=].

          For example, if |keyframe| has
          a value of ''12pt'' for the 'border-width' [=shorthand property=],
          the user agent will [=compute a property value=] of ''16px''
          for each of the [=longhand properties=]:
          'border-bottom-width', 'border-left-width',
          'border-right-width', and 'border-top-width'.
          As a result, |computed keyframe| would <em>not</em> have
          a value for the 'border-width' property,
          but would instead include each of the longhand properties,
          each with the value ''16px''.

          If conflicts arise when expanding shorthand properties
          or replacing logical properties with physical properties,
          apply the following rules in order until the conflict is resolved:

          1. Longhand properties override shorthand properties
              (e.g. 'border-top-color' overrides 'border-top').
          1. Shorthand properties with fewer longhand components
              override those with more longhand components
              (e.g. 'border-top' overrides 'border-color').
          1. Physical properties override logical properties.
          1. For shorthand properties with an equal number of longhand components,
              properties whose IDL name
              (see the [=CSS property to IDL attribute=] algorithm [[!CSSOM]])
              appears earlier when sorted in ascending order
              by the Unicode codepoints that make up each IDL name,
              override those who appear later.

  1. Apply the procedure to [=compute missing keyframe offsets=]
      to |computed keyframes|.

  1. Return |computed keyframes|.


### The effect value of a keyframe effect ### {#the-effect-value-of-a-keyframe-animation-effect}

  The [=effect value=] of a single property referenced by a [=keyframe effect=]
  as one of its [=target property|target properties=],
  for a given |iteration progress|,
  <var ignore>iteration index</var>
  and |underlying value|
  is calculated as follows.

  1. If |iteration progress| is [=unresolved=]
      abort this procedure.

  1. Let |target property| be the [=longhand property=]
      for which the [=effect value=] is to be calculated.

  1. If [=animation type=] of the |target property| is [=not animatable=]
      abort this procedure since the effect cannot be applied.

  1. If the  [=keyframe effect=] does not have an [=effect target=],
      or if the [=effect target=] cannot have computed property values calculated,
      abort this procedure.

  1. Define the <dfn>neutral value for composition</dfn>
      as a value which, when combined with an [=underlying value=]
      using the [=composite operation add|add=] [=composite operation=],
      produces the [=underlying value=].

  1. Let |property-specific keyframes| be
      the result of getting the set of [=computed keyframes=]
      for this [=keyframe effect=].

  1. Remove any [=keyframes=] from |property-specific keyframes|
      that do not have a property value for |target property|.

  1. If |property-specific keyframes| is empty,
      return |underlying value|.

  1. If there is no [=keyframe=] in |property-specific keyframes|
      with a [=computed keyframe offset=] of 0,
      create a new [=keyframe=]
      with a [=computed keyframe offset=] of 0,
      a property value set to the [=neutral value for composition=],
      and a [=composite operation=] of [=composite operation add|add=],
      and prepend it to the beginning of |property-specific keyframes|.

  1. Similarly, if there is no [=keyframe=] in |property-specific keyframes|
      with a [=computed keyframe offset=] of 1,
      create a new [=keyframe=]
      with a [=computed keyframe offset=] of 1,
      a property value set to the [=neutral value for composition=],
      and a [=composite operation=] of [=composite operation add|add=],
      and append it to the end of |property-specific keyframes|.

  1. Let |interval endpoints| be an empty sequence of keyframes.

  1. Populate |interval endpoints| by following the steps
      from the first matching condition below:

      <dl class=switch>

      : If |iteration progress| < 0
          and there is more than one [=keyframe=]
          in |property-specific keyframes|
          with a [=computed keyframe offset=] of 0,
      ::
          Add the first [=keyframe=] in |property-specific keyframes|
          to |interval endpoints|.

      : If |iteration progress| ≥ 1
          and there is more than one [=keyframe=]
          in |property-specific keyframes|
          with a [=computed keyframe offset=] of 1,
      ::
          Add the last [=keyframe=] in |property-specific keyframes|
          to |interval endpoints|.

      : Otherwise,
      ::

          1. Append to |interval endpoints|
              the last [=keyframe=] in |property-specific keyframes|
              whose [=computed keyframe offset=] is
              less than or equal to |iteration progress| and less than 1.
              If there is no such [=keyframe=]
              (because, for example, the [=iteration progress=] is negative),
              add the last [=keyframe=]
              whose [=computed keyframe offset=] is 0.

          1. Append to |interval endpoints|
              the next [=keyframe=] in |property-specific keyframes|
              after the one added in the previous step.

      </dl>

  1. For each |keyframe| in |interval endpoints|:

      1. If |keyframe| has a [=composite operation=]
          that is <em>not</em> [=composite operation replace|replace=],
          or |keyframe| has no [=composite operation=]
          and the [=composite operation=] of this [=keyframe effect=]
          is <em>not</em> [=composite operation replace|replace=],
          then perform the following steps:

          1. Let |composite operation to use| be
              the [=composite operation=] of |keyframe|,
              or if it has none,
              the [=composite operation=] of this [=keyframe effect=].

          1. Let |value to combine| be
              the property value of |target property| specified on |keyframe|.

          1. Replace the property value of |target property| on |keyframe|
              with the result of combining
              |underlying value| (|V|<sub>a</sub>) and
              |value to combine| (|V|<sub>b</sub>)
              using the procedure for the |composite operation to use|
              corresponding to the |target property|'s [=animation type=].

  1. If there is only one keyframe in |interval endpoints|
      return the property value of |target property| on that keyframe.

  1. Let |start offset| be the [=computed keyframe offset=]
      of the first keyframe in |interval endpoints|.

  1. Let |end offset| be the [=computed keyframe offset=]
      of last keyframe in |interval endpoints|.

  1. Let |interval distance| be the result of evaluating
      <code>(<var>iteration progress</var> − <var>start offset</var>)
            / (<var>end offset</var> − <var>start offset</var>)</code>.

  1. Let |transformed distance| be the result of evaluating
      the [=easing function=] associated with
      the first keyframe in |interval endpoints|
      passing |interval distance| as the input progress.

  1. Return the result of applying
      the [=interpolation|interpolation procedure=] defined
      by the [=animation type=] of the |target property|
      to the values of the |target property|
      specified on the two keyframes in |interval endpoints|,
      taking the first such value as |V|<sub>start</sub>
      and the second as |V|<sub>end</sub>
      and using |transformed distance|
      as the interpolation parameter <var ignore>p</var>.

  <wpt>
    animation-model/keyframe-effects/effect-value-interval-distance.html
    animation-model/keyframe-effects/effect-value-iteration-composite-operation.html
    animation-model/keyframe-effects/effect-value-opacity-replaced-effect-in-shadow-root.html
    animation-model/keyframe-effects/effect-value-opacity-replaced-effect.html
    animation-model/keyframe-effects/effect-value-overlapping-keyframes.html
    animation-model/keyframe-effects/effect-value-replaced-animations.html
    animation-model/keyframe-effects/effect-value-transformed-distance.html
  </wpt>

  <div class=note>

    Note that this procedure assumes the following
    about the list of [=keyframes=] specified on the effect:

    * Each [=keyframe=] has a specified [=computed keyframe offset=]
        in the range [0, 1].
    * The list of [=keyframes=] is sorted in ascending order
        by [=computed keyframe offset=].
    * For a given property,
        there is at most one specified property value on each keyframe.

    It is the responsibility of the user of the model
    (for example, a declarative markup or programming interface)
    to ensure these conditions are met.

    For example, for the <a href="#programming-interface">programming interface</a>
    defined by this specification,
    these conditions are met by
    the procedure to produce the [=computed keyframes=]
    that become the input to this procedure.

  </div>

  Note: this procedure permits overlapping [=keyframes=].
  The behavior is that
  at the point of overlap the output value jumps
  to the value of the last defined [=keyframe=] at that offset.
  For overlapping keyframes at 0 or 1,
  the output value for [=iteration progress=] values
  less than 0 or greater than or equal to 1
  is the value of
  the first [=keyframe=] or the last [=keyframe=] in |keyframes| respectively.

  <div class=note>
    Note that [=computed keyframes=] are “live”:
    user-agents behave as if they are recreated
    every time the [=effect value=] is calculated.

    For example, if there is an ongoing transition
    on the 'font-size' property from <code>10px</code> to <code>20px</code>,
    a property value specified as <code>1em</code> in a [=keyframe=]
    would during [[#calculating-computed-keyframes|keyframe computation]]
    resolve against the [=computed value=]
    in the range [<code>10px</code>, <code>20px</code>]
    produced by the transition on 'font-size'.
  </div>

  <div class=issue>
    In the presence of certain easing functions,
    the input [=iteration progress=] to an animation effect
    is not limited to the range [0, 1].
    Currently, however, keyframe offsets <em>are</em> limited to the range [0, 1]
    and property values are simply extrapolated
    for input [=iteration progress=] values outside this range.

    We have considered removing this restriction
    since some cases exist where it is useful
    to be able to specify non-linear changes in property values
    at [=iteration progress=] values outside the range [0, 1].
    One example is an animation that interpolates from green to yellow
    but has an overshoot easing function
    that makes it temporarily interpolate “beyond” yellow to red
    before settling back to yellow.

    While this effect could be achieved by
    modification of the keyframes and easing function,
    this approach seems to break the model's separation
    of timing concerns from animation effects.

    It is not clear how this effect should be achieved
    but we note that allowing keyframe offsets outside [0, 1]
    can make the currently specified behavior,
    where keyframes at offset 0 and 1 are synthesized as necessary,
    inconsistent.

    See <a href="http://lists.w3.org/Archives/Public/public-fx/2013AprJun/0184.html">section 4
    (Keyframe offsets outside [0, 1]) of minuted discussion from Tokyo 2013 F2F</a>.

    <a href="https://github.com/w3c/csswg-drafts/issues/2081">&lt;https://github.com/w3c/csswg-drafts/issues/2081&gt;</a>
  </div>

Combining effects {#combining-effects}
-----------------
<div class=informative-bg>
<em>This section is non-normative</em>

  After calculating the [=effect values=] for a [=keyframe effect=],
  they are applied to the [=animation effect=]’s [=target property|target properties=].

  Since it is possible for multiple [=in effect=] [=keyframe effects=]
  to target the same property
  it is often necessary to combine the results
  of several [=keyframe effects=] together.
  This process is called <dfn lt="composite | composition">compositing</dfn>
  and is based on establishing an [=effect stack=]
  for each property targeted by an [=in effect=] [=animation effect=].

  After [=compositing=] the results of [=keyframe effects=] together,
  the composited result
  is combined with other values specified for the [=target property=].

  The arrangement is illustrated below:

  <figure>
    <img src="images/animation-cascade.svg" width="500"
         alt="Overview of the application of effect values to their target properties">
    <figcaption>
      Overview of the application of [=effect values=]
      to their [=target properties=].<br>
      The results of [=keyframe effects=] targeting the same property
      are composited together using an [=effect stack=].<br>
      The result of this composition is then inserted into the CSS cascade
      at an appropriate point.
    </figcaption>
  </figure>

  For the first part of this operation--
  combining [=effect values=] that target the same [=target property|property=]--
  it is necessary to determine both
  <em>how</em> [=keyframe effects=] are combined with one another,
  as well as the <em>order</em> in which they are applied,
  that is, their relative <em>composite order</em>.

  The matter of <em>how</em> [=effect values=] are combined
  is governed by the [=composite operation=]
  of the corresponding [=keyframe effects=].

  The relative <em>composite order</em> of [=effect values=]
  is determined by an [=effect stack=]
  established for each animated property.
</div>

### Animation classes ### {#animation-classes}

  This specification provides a common animation model
  intended to be used by other specifications
  that define markup or programming interfaces on top of this model.
  The particular markup or programming interface
  that generated an [=animation=]
  defines its <dfn>animation class</dfn>.

  Further specifications may define specialized behavior for composite ordering
  between different classes of animations or within a particular class.

<div class=informative-bg>
<em>This section is non-normative</em>

  For example, animations whose [=animation class|class=] is “CSS animation”
  are defined as having a <em>higher</em> composite order
  than animations whose class is “CSS transition”
  but <em>lower</em> than other animations without a specific class.

  Within the set of “CSS animation” objects,
  specialized composite ordering is defined
  based on the 'animation-name' property
  amongst other factors.

</div>

### The effect stack ### {#the-effect-stack}

  An <dfn>effect stack</dfn> is associated with
  each property [=target property|targeted=]
  by one or more [=keyframe effects=].
  The [=effect stack=] establishes
  the relative composite order of [=keyframe effects=].

  The relative
  <dfn lt="animation composite order" local-lt="composite order" export>composite order</dfn>
  of any two [=keyframe effects=] |A| and |B| within an [=effect stack=]
  is established by comparing their properties as follows:

  1. Sort |A| and |B|
      by applying the following conditions in turn
      until the order is resolved,

      1. If |A| and |B|'s [=animation effect/associated animations=] differ
          by [=animation class|class=],
          sort by any inter-class composite order
          as defined for the corresponding classes.

      1. If |A| and |B| are still not sorted,
          sort by any [=animation class|class=]-specific composite order
          defined by the common class of |A| and |B|'s
          [=animation effect/associated animations=].

      1. If |A| and |B| are still not sorted,
          sort by the position of their [=animation effect/associated animations=]
          in the [=global animation list=].

  [=Animation effects=] that sort earlier have <em>lower</em> composite order.

### Calculating the result of an effect stack ### {#calculating-the-result-of-an-effect-stack}

  In order to calculate the final value of an [=effect stack=],
  the [=effect values=] of each [=keyframe effect=] in the stack
  are combined in composite order.

  Each step in the process of evaluating an [=effect stack=]
  takes an <dfn>underlying value</dfn> as input.

  For each [=keyframe effect=] in the stack,
  the appropriate [=effect value=] from the [=keyframe effect=]
  is combined with the [=underlying value=] to produce a new value.
  This resulting value becomes the [=underlying value=]
  for combining the next [=keyframe effect=] in the stack.

  The final value of an [=effect stack=],
  called the <dfn>composited value</dfn>,
  is simply the result of combining the [=effect value=]
  of the final (highest composite order) [=keyframe effect=] in the stack
  with the [=underlying value=] at that point.

### Effect composition ### {#effect-composition}

  The specific operation used
  to combine an [=effect value=] with an[=underlying value=]
  is determined by the <dfn>composite operation</dfn>
  of the [=keyframe effect=] that produced the [=effect value=].

  This specification defines three [=composite operations=]
  as follows:

  : <dfn lt="composite operation replace">replace</dfn>
  ::
      The result of compositing the [=effect value=]
      with the [=underlying value=]
      is simply the [=effect value=].

  : <dfn lt="composite operation add">add</dfn>
  ::
      The [=effect value=] is [=value addition|added=]
      to the [=underlying value=].
      For [=animation types=] where the [=value addition|addition operation=]
      is defined such that it is not commutative,
      the order of the operands is
      <code><a>underlying value</a> + <a>effect value</a></code>.

  : <dfn lt="composite operation accumulate">accumulate</dfn>
  ::
      The [=effect value=] is [=value accumulation|accumulated=]
      onto the [=underlying value=].
      For [=animation types=] where the [=value accumulation|accumulation operation=]
      is defined such that it is not commutative,
      the order of the operands is [=underlying value=]
      followed by [=effect value=].

  <wpt>
    animation-model/combining-effects/effect-composition.html
  </wpt>

### Applying the composited result ### {#applying-the-composited-result}

  Applying a [=composited value=] to a [=target property=]
  is achieved by adding a specified value to the CSS cascade.

  The level of the cascade to which this specified value is added
  depends on the [=animation class|class=] of the [=animation=]
  [=animation effect/associated animation|associated with=]
  the effect with the highest composite order in the [=effect stack=]
  for a given property.
  By default, the specified value is added to
  the [=Animation Origin=] of the cascade. [[!CSS-CASCADE-3]]

  <wpt>
    animation-model/combining-effects/applying-the-composited-result.html
  </wpt>

  <div class=example>
    For example, if the effect with the highest composite order
    is associated with a “CSS transition”-class animation,
    the [=composited value=] will be added to
    the [=Transition Origin=] of the cascade.
  </div>

  The [=composited value=] calculated for a CSS [=target property=]
  is applied using the following process:

  1. Calculate the |base value| of the property
      as the value generated for that property
      by finding the [=computed value=] for that property
      in the absence of animations.

  2. Establish the [=effect stack=] for the property
      (see [[#the-effect-stack]]).

  3. Calculate the [=composited value=] of the [=effect stack=]
      passing in the |base value| of the property
      as the initial [=underlying value=]
      (see [[#calculating-the-result-of-an-effect-stack]]).

  4. Insert the [=composited value=] into the CSS cascade
      at the level defined for the [=animation class|class=] of
      the [=animation=] [=animation effect/associated animation|associated with=]
      the effect at the top of the [=effect stack=]
      established for the [=target property=].

Replacing animations {#replacing-animations}
--------------------

<div class=informative-bg>
<em>This section is non-normative</em>

  Using the programming interface defined in this specification,
  it is possible to repeatedly trigger new animations
  that contribute to an element's animated style indefinitely.

  For example, consider the following code:

  <div class=example>
    <pre highlight=javascript>
      elem.addEventListener('mousemove', evt => {
        circle.animate(
          { transform: \`translate(${evt.clientX}px, ${evt.clientY}px)\` },
          { duration: 500, fill: 'forwards' }
        );
      });
    </pre>
  </div>

  This will generate a new forwards-filling animation
  each time the mouse is moved,
  quickly producing hundreds, even thousands of forwards-filling animations.

  If the user agent needed to retain <em>all</em> such animations,
  the list of animations would grow in an unbounded fashion,
  producing a memory leak.

  This section defines a mechanism
  that causes overridden animations to be automatically removed
  unless the author explicitly requests they be retained.

</div>

### Replace state ### {#animation-replace-state}

  An [=animation=] maintains a <dfn>replace state</dfn>
  that can be one of the following values:

  * <dfn lt="active replace state">active</dfn>
  * <dfn lt="removed replace state">removed</dfn>
  * <dfn lt="persisted replace state">persisted</dfn>

  The initial value of an [=animation=]'s [=replace state=]
  is [=active replace state|active=].

  The [=animation effects=] of an [=animation=]
  whose [=replace state=] is [=removed replace state|removed=]
  are not included in the [=effect stacks=] of their [=target properties=].

### Removing replaced animations ### {#removing-replaced-animations}

  An [=animation=] is
  <dfn lt="replaceable animation" local-lt="replaceable">replaceable</dfn>
  if <em>all</em> of the following conditions are true:

  * The existence of the [=animation=] is <em>not</em> prescribed by markup.
      That is, it is <em>not</em>
      a CSS animation with an [=owning element (animation)|owning element=],
      nor a CSS transition with an [=owning element (transition)|owning element=].
  * The [=animation=]'s [=play state=] is [=play state/finished=].
  * The [=animation=]'s [=replace state=] is <em>not</em>
      [=removed replace state|removed=].
  * The [=animation=] is associated with
      a [=monotonically increasing=] [=timeline=].
  * The [=animation=] has an [=associated effect=].
  * The [=animation=]'s [=associated effect=] is [=in effect=].
  * The [=animation=]'s [=associated effect=] has an [=effect target=].

  When asked to <dfn>remove replaced animations</dfn>
  for a {{Document}}, |doc|,
  then for every [=animation=], |animation|, that:

  * has an [=associated with an animation|associated=] [=animation effect=]
      whose [=effect target=] is a [=descendant=] of |doc|, and

  * is [=replaceable=], and

  * has a [=replace state=] of [=active replace state|active=], and

  * for which there exists for each [=target property=]
      of every [=animation effect=]
      [=associated with an animation|associated=] with |animation|,
      an [=animation effect=] associated with a [=replaceable=] [=animation=]
      with a higher [=composite order=] than |animation|
      that includes the same [=target property=]

  perform the following steps:

  1.  Set |animation|'s [=replace state=] to [=removed replace state|removed=].

  1.  [=create an event|Create=] an {{AnimationPlaybackEvent}}, |removeEvent|.

  1.  Set |removeEvent|'s {{Event/type}} attribute to [=remove event|remove=].

  1.  Set |removeEvent|'s {{AnimationPlaybackEvent/currentTime}} attribute
       to the [=animation/current time=] of |animation|.

  1.  Set |removeEvent|'s {{AnimationPlaybackEvent/timelineTime}} attribute
       to the [=timeline/current time=]
       of the [=timeline=] with which |animation| is associated.

  1.  If |animation| has a [=document for timing=],
       then append |removeEvent|
       to its [=document for timing=]'s [=pending animation event queue=]
       along with its target, |animation|.
       For the [=scheduled event time=],
       use the result of applying the procedure to convert
       [=timeline time to origin-relative time=]
       to the [=timeline/current time=] of the [=timeline=]
       with which |animation| is associated.

       Otherwise,
       [=queue a task=] to [=dispatch=] |removeEvent| at |animation|.
       The task source for this task is
       the [=DOM manipulation task source=].

Side effects of animation {#side-effects-section}
-------------------------

  For every property targeted by at least one [=animation effect=]
  that is [=current=] or [=in effect=],
  and which is associated with an [=animation=]
  whose [=replace state=] is <em>not</em> [=removed replace state|removed=],
  the user agent must act as if
  the 'will-change' property [[!css-will-change-1]] on the [=effect target=]
  includes the property.

  <wpt>
    animation-model/side-effects-of-animations-current.html
    animation-model/side-effects-of-animations-in-effect.html
    animation-model/side-effects-of-animations-none.html
  </wpt>

  Note: As a result of the above requirement,
  if an animation targets, for example,
  the 'transform' property of an element,
  a [=stacking context=] will be created for the [=effect target=]
  so long as the [=animation=] is in the [=animation effect/before phase=],
  the [=animation effect/active phase=] or,
  if it has a [=fill mode=] of [=fill mode/forwards=] or [=fill mode/both=],
  the [=animation effect/after phase=].

<!-- End of animation model -->


<!--
                         ███    ████████  ████
                        ██ ██   ██     ██  ██
                       ██   ██  ██     ██  ██
                      ██     ██ ████████   ██
                      █████████ ██         ██
                      ██     ██ ██         ██
                      ██     ██ ██        ████
-->

Programming interface {#programming-interface}
=====================

<div class=informative-bg>
<em>This section is non-normative</em>

  In addition to the abstract model described above,
  Web Animations also defines a programming interface to the model.
  This interface can be used
  to inspect and extend animations produced by declarative means
  or for directly producing animations
  when a procedural approach is more suitable.

</div>

Time values in the programming interface {#time-values-in-the-programming-interface}
----------------------------------------

  [=Time values=] are represented in the programming interface
  with the type `double`.
  [=Unresolved=] time values are represented
  by the value `null`.

The {{AnimationTimeline}} interface {#the-animationtimeline-interface}
-----------------------------------

  [=Timelines=] are represented in the Web Animations API
  by the {{AnimationTimeline}} interface.

  <xmp class=idl>
    [Exposed=Window]
    interface AnimationTimeline {
      readonly attribute double? currentTime;
    };
  </xmp>

  <div dfn-type=attribute class=attributes
       dfn-for="AnimationTimeline">

  : <dfn>currentTime</dfn>
  ::
      Returns the [=timeline/current time=] for this timeline
      or `null` if this timeline is [=inactive timeline|inactive=].

  </div>

The {{DocumentTimeline}} interface {#the-documenttimeline-interface}
----------------------------------

  [=Document timelines=],
  including the [=default document timeline=],
  are represented in the Web Animations API
  by the {{DocumentTimeline}} interface.

  <xmp class=idl>
    dictionary DocumentTimelineOptions {
      DOMHighResTimeStamp originTime = 0;
    };

    [Exposed=Window]
    interface DocumentTimeline : AnimationTimeline {
      constructor(optional DocumentTimelineOptions options = {});
    };
  </xmp>

  <div dfn-type=dict-member class=members
       dfn-for="DocumentTimelineOptions">

  : <dfn>originTime</dfn>
  ::
      The [=origin time=] for the timeline
      specified as a real number of milliseconds
      relative to the [=time origin=].

  </div>

  <div dfn-type=constructor class=constructors
       dfn-for="DocumentTimeline">

  : <dfn lt="DocumentTimeline(options)">DocumentTimeline (|options|)</dfn>
  ::
      Creates a new {{DocumentTimeline}}.
      The {{Document}} with which the timeline is associated
      is the {{Document}} [=document associated with a window|associated=]
      with the {{Window}} that is the [=current global object=].

      <div dfn-type=argument class=parameters
          dfn-for="DocumentTimeline/DocumentTimeline(options)">

      : <dfn>options</dfn>
      ::  Configuration parameters for the newly-created timeline.
          This specification defines only the
          {{DocumentTimelineOptions/originTime}} member
          but other specifications may extend this set.

      </div>

  </div>

The {{Animation}} interface {#the-animation-interface}
---------------------------

  [=Animations=] are represented in the Web Animations API
  by the <dfn interface>Animation</dfn> interface.

  <xmp class=idl>
    [Exposed=Window]
    interface Animation : EventTarget {
      constructor(optional AnimationEffect? effect = null,
                  optional AnimationTimeline? timeline);
               attribute DOMString                id;
               attribute AnimationEffect?         effect;
               attribute AnimationTimeline?       timeline;
               attribute double?                  startTime;
               attribute double?                  currentTime;
               attribute double                   playbackRate;
      readonly attribute AnimationPlayState       playState;
      readonly attribute AnimationReplaceState    replaceState;
      readonly attribute boolean                  pending;
      readonly attribute Promise<Animation>       ready;
      readonly attribute Promise<Animation>       finished;
               attribute EventHandler             onfinish;
               attribute EventHandler             oncancel;
               attribute EventHandler             onremove;
      undefined cancel();
      undefined finish();
      undefined play();
      undefined pause();
      undefined updatePlaybackRate(double playbackRate);
      undefined reverse();
      undefined persist();
      [CEReactions]
      undefined commitStyles();
    };
  </xmp>

  <div dfn-type=constructor class=constructors
       dfn-for="Animation">

  : <dfn lt="Animation(effect, timeline)">Animation (|effect|, |timeline|)</dfn>
  ::
      Creates a new {{Animation}} object using the following procedure:

      1. Let |animation| be a new {{Animation}} object.

      2. Run the procedure to [=set the timeline of an animation=]
          on |animation|
          passing |timeline| as the <var ignore>new timeline</var>;
          or, if the |timeline| argument is missing,
          passing the [=default document timeline=]
          of the {{Document}} [=document associated with a window|associated=]
          with the {{Window}} that is the [=current global object=].

      3. Run the procedure to [=set the associated effect of an animation=]
          on |animation|
          passing |source| as the <var ignore>new effect</var>.

      <div dfn-type=argument class=parameters
           dfn-for="Animation/Animation(effect, timeline)">

      : <dfn>effect</dfn>
      ::  An optional value which, if not `null`,
          specifies the [=associated effect=] to assign
          to the newly created [=animation=].

      : <dfn>timeline</dfn>
      ::  An optional value which, if present,
          specifies the [=timeline=] with which to associate
          the newly-created [=animation=].
          If missing, the [=default document timeline=]
          of the {{Document}} [=document associated with a window|associated=]
          with the {{Window}} that is the [=current global object=] is used.

      </div>

      <wpt>
        interfaces/Animation/constructor.html
      </wpt>

  </div>

  <div dfn-type=attribute class=attributes
       dfn-for="Animation">

  : <dfn>id</dfn>
  ::
      A string used to identify the animation.

    <wpt>
      interfaces/Animation/id.html
    </wpt>

  : <dfn>effect</dfn>
  ::
      The [=associated effect=] of this animation.
      Setting this attribute updates the object's [=associated effect=]
      using the procedure to [=set the associated effect of an animation=].

    <wpt>
      interfaces/Animation/effect.html
    </wpt>

  : <dfn>timeline</dfn>
  ::
      The [=timeline=] associated with this animation.
      Setting this attribute updates the object's [=timeline=]
      using the procedure to [=set the timeline of an animation=].

  : <dfn>startTime</dfn>
  ::
      Returns the [=start time=] of this animation.
      Setting this attribute updates the [=start time=]
      using the procedure to [=set the start time=]
      of this object to the new value.

  : <dfn>currentTime</dfn>
  ::
      The [=animation/current time=] of this animation.
      Setting this attribute follows the procedure to [=set the current time=]
      of this object to the new value.

  : <dfn>playbackRate</dfn>
  ::
      The [=playback rate=] of this animation.
      Setting this attribute follows the procedure to [=set the playback rate=]
      of this object to the new value.

      <div class=note>

        Setting this attribute performs
        a synchronous update to the [=playback rate=]
        meaning that it does not make any attempt
        to synchronize with the playback state of animations running
        on a separate process or thread.
        As a result, setting the {{Animation/playbackRate}}
        for an in-flight animation
        can cause it to jump.

        To set the [=playback rate=] for an in-flight animation
        such that it smoothly updates,
        use the asynchronous {{updatePlaybackRate()}} method.

      </div>

  : <dfn>playState</dfn>
  ::
      The [=play state=] of this animation.

  : <dfn>replaceState</dfn>
  ::
      The [=replace state=] of this animation.

  : <dfn>pending</dfn>
  ::
      Returns true if this animation has
      a [=pending play task=] or a [=pending pause task=].

    <wpt>
      interfaces/Animation/pending.html
    </wpt>

  : <dfn>ready</dfn>
  ::
      Returns the [=current ready promise=] for this object.

    <wpt>
      interfaces/Animation/ready.html
    </wpt>

  : <dfn>finished</dfn>
  ::
      Returns the [=current finished promise=] for this object.

    <wpt>
      interfaces/Animation/finished.html
    </wpt>

  : <dfn>onfinish</dfn>
  ::
      The event handler for the [=finish event=].

    <wpt>
      interfaces/Animation/onfinish.html
    </wpt>

  : <dfn>oncancel</dfn>
  ::
      The event handler for the [=cancel event=].

    <wpt>
      interfaces/Animation/oncancel.html
    </wpt>

  : <dfn>onremove</dfn>
  ::
      The event handler for the [=remove event=].

    <wpt>
      interfaces/Animation/onremove.html
    </wpt>

  </div>

  <div dfn-type=method class=methods
       dfn-for="Animation">

  : <dfn lt="cancel()">void cancel()</dfn>
  ::
      Clears all effects caused by this animation
      and aborts its playback by running the [=cancel an animation=] procedure
      for this object.

      <wpt>
        interfaces/Animation/cancel.html
      </wpt>

  : <dfn lt="finish()">void finish()</dfn>
  ::
      [=Seeks=] the animation to
      the [=associated effect end=] in the current direction
      by running the [=finish an animation=] procedure
      for this object.

      <div class=exceptions>

      : {{DOMException}} of type "{{InvalidStateError}}"
      ::
          Raised if this animation's [=playback rate=] is zero,
          or if this animation's [=playback rate=] is > zero
          and the [=associated effect end=] is infinity.

      </div>

  : <dfn lt="play()">void play()</dfn>
  ::
      Begins or resumes playback of the animation
      by running the procedure to [=play an animation=]
      passing true as the value of the |auto-rewind| flag.

  : <dfn lt="pause()">void pause()</dfn>
  ::
      Suspends the playback of this animation
      by running the procedure to [=pause an animation=]
      for this object.

    <wpt>
      interfaces/Animation/pause.html
    </wpt>

  : <dfn lt="updatePlaybackRate(playbackRate)">void updatePlaybackRate(<var ignore>playbackRate</var>)</dfn>
  ::
      Performs an asynchronous update of the [=playback rate=] of this animation
      by performing the [=seamlessly update the playback rate=] procedure,
      passing {{Animation/updatePlaybackRate(playbackRate)/playbackRate}}
      as the <var ignore>new playback rate</var>.

      <div dfn-type=argument class=parameters
           dfn-for="Animation/updatePlaybackRate(playbackRate)">

      : <dfn>playbackRate</dfn>
      ::
          A finite real number specifying
          the updated playback rate to use.

      </div>

  : <dfn lt="reverse()">void reverse()</dfn>
  ::
      Inverts the [=playback rate=] of this animation
      and plays it using the [=reverse an animation=] procedure
      for this object.
      As with {{Animation/play()}},
      this method unpauses the animation and,
      if the animation has already finished playing in the reversed direction,
      [=seeks=] to the start of the [=associated effect=].

  : <dfn lt="persist()">void persist()</dfn>
  ::
      Sets this animation's [=replace state=]
      to [=persisted replace state|persisted=].

  : <dfn lt="commitStyles()">void commitStyles()</dfn>
  ::
      Writes the current [=effect values=]
      produced by this animation's [=animation effects=]
      to their corresponding [=effect targets=]' inline style
      using the [=commit computed styles=] procedure.

      Unlike most other methods defined on this interface,
      calling this method <em>does</em> trigger a [=style change event=]
      (see [[#model-liveness]]).

      <wpt>
        interfaces/Animation/commitStyles.html
      </wpt>

      <div class=note>

        In order to simplify the common case
        of persisting a completed animation,
        the procedure to [=commit computed styles=]
        uses endpoint-*inclusive* timing (see [[#interval-timing]])
        when determining the phase of the animation
        (see [[#animation-effect-phases-and-states]]).

        As a result, the following code will persist
        the `transform: translateY(100px)` style in specified style
        despite not having a
        [=fill mode=] of [=fill mode/forwards=] or [=fill mode/both=].

        <pre highlight=javascript>
          elem.animate({ transform: 'translateY(100px)' }, 200).finished.then(() => {
            elem.commitStyles();
          });
        </pre>

      </div>

      <div class=note>

        Since the procedure to [=commit computed styles=]
        includes the [=effect values=] for the animation
        even if it is [=removed replace state|removed=],
        this method is useful for retaining the effect of an animation
        after it has been replaced (see [[#removing-replaced-animations]])
        without retaining the actual animation.

        Note that the values committed are the <em>computed</em> values
        produced by the [=animation effects=]
        at the time when this method is called.
        Since these values are computed values,
        they do not reflect to changes to context
        such as responding to changes to CSS variables
        or recalculating ''em'' units
        based on changes to the computed ''font-size''
        in the way the values produced by a live animation would.

        In order to retain full fidelity of a filling animation's result
        after it has been replaced (see [[#replacing-animations]]),
        the {{Animation/persist()}} method can be used,
        but note that doing so will mean
        the animation continues to consume resources.

      </div>

  </div>

  <div algorithm>
    To <dfn>commit computed styles</dfn> for an [=animation=], |animation|:

    1. Let |targets| be the [=ordered set|set=]
        of all [=effect targets=] for [=animation effects=]
        [=associated with an animation|associated=] with |animation|.

    1. [=list/iterate|For each=] |target| in |targets|:

        1. If |target| is not an element capable of having
            a [=style attribute=] [[!CSS-STYLE-ATTR]]
            (for example, it is a [=pseudo-element=]
             or is an element in a document format
             for which style attributes are not defined)
            [=throw=] a "{{NoModificationAllowedError}}" {{DOMException}}
            and abort these steps.

        1. If, after applying any pending style changes,
            |target| is not [=being rendered=],
            [=throw=] an "{{InvalidStateError}}" {{DOMException}}
            and abort these steps.

            ISSUE: The definition of [=being rendered=] [[!HTML]]
            with regards to ''display: contents'' is still
            <a href="https://github.com/whatwg/html/issues/1837">under discussion</a>.
            For the purpose of this procedure,
            we assume that an element with ''display: contents''
            that otherwise would have associated layout boxes
            (i.e. it is [=connected=]
             and not part of a ''display: none'' subtree)
            <em>is</em> being rendered.

        1. Let |inline style| be the result
            of getting the [=CSS declaration block=]
            corresponding to |target|'s [=style attribute=].
            If |target| does not [=has an attribute|have=]
            a [=style attribute=],
            let |inline style| be a new empty [=CSS declaration block=]
            with the [=CSSStyleDeclaration/owner node=] set to |target|.

        1. Let |targeted properties| be the [=ordered set|set=]
            of physical longhand properties
            that are a [=target property=]
            for at least one [=animation effect=]
            [=associated with an animation|associated=] with |animation|
            whose [=effect target=] is |target|.

        1.  For each property, |property|, in |targeted properties|:

            1. Let |partialEffectStack| be a copy of the [=effect stack=]
                for |property| on |target|.

            1. If |animation|'s [=replace state=]
                is [=removed replace state|removed=],
                add all [=animation effects=]
                [=associated with an animation|associated=] with |animation|
                whose [=effect target=] is |target|
                and that include |property|
                as a [=target property=] to |partialEffectStack|.

            1. Remove from |partialEffectStack| any [=animation effects=]
                whose [=associated with an animation|associated=] [=animation=]
                has a higher [=composite order=] than |animation|.

            1. Let |effect value| be the result of calculating
                the result of |partialEffectStack| for |property|
                using |target|'s computed style
                (see [[#calculating-the-result-of-an-effect-stack]]) and
                setting the [=endpoint-inclusive active interval=] flag
                to true
                when calculating the animation effect phase
                (see [[#animation-effect-phases-and-states]]).

            1. [=Set a CSS declaration=] of |property| for |effect value|
                in |inline style|.

        1.  [=Update style attribute for=] |inline style|.
  </div>

### The {{AnimationPlayState}} enumeration ### {#the-animationplaystate-enumeration}

  <xmp class=idl>
    enum AnimationPlayState { "idle", "running", "paused", "finished" };
  </xmp>

  <dl dfn-type=enum-value
      dfn-for="AnimationPlayState">
  : <dfn>idle</dfn>
  ::  Corresponds to the [=idle play state=].
  : <dfn>running</dfn>
  ::  Corresponds to the [=running play state=].
  : <dfn>paused</dfn>
  ::  Corresponds to the [=paused play state=].
  : <dfn>finished</dfn>
  ::  Corresponds to the [=finished play state=].

  </dl>

### The {{AnimationReplaceState}} enumeration ### {#the-animationreplacestate-enumeration}

  <xmp class=idl>
    enum AnimationReplaceState { "active", "removed", "persisted" };
  </xmp>

  <dl dfn-type=enum-value
      dfn-for="AnimationReplacedState">
  : <dfn>active</dfn>
  ::  Corresponds to the [=active replace state=].
  : <dfn>removed</dfn>
  ::  Corresponds to the [=removed replace state=].
  : <dfn>persisted</dfn>
  ::  Corresponds to the [=persisted replace state=].

  </dl>

The {{AnimationEffect}} interface {#the-animationeffect-interface}
---------------------------------

  [=Animation effects=] are represented in the Web Animations API by the
  abstract {{AnimationEffect}} interface.

  <xmp class=idl>
    [Exposed=Window]
    interface AnimationEffect {
        EffectTiming         getTiming();
        ComputedEffectTiming getComputedTiming();
        undefined            updateTiming(optional OptionalEffectTiming timing = {});
    };
  </xmp>

  Note: In future, we may expose
  <code>any onupdate (double?     progress,
                      double      currentIteration,
                      Animatable? target,
                      any         underlyingValue)</code>
  so that the animation effects can be driven apart from the timing model.

  <div dfn-type=method class=methods
       dfn-for="AnimationEffect">

  : <dfn>getTiming()</dfn>
  ::
      Returns the specified timing properties
      for this [=animation effect=].

      For the correspondence between
      the members of the returned {{EffectTiming}} object
      and properties of the [[#timing-model|timing model]],
      see the {{EffectTiming}} interface.

  : <dfn>getComputedTiming()</dfn>
  ::
      Returns the calculated timing properties
      for this [=animation effect=].

      Although some of the attributes
      of the object returned by {{AnimationEffect/getTiming()}}
      and {{AnimationEffect/getComputedTiming()}}
      are common,
      their values can differ in the following ways:

      * {{EffectTiming/duration}} &ndash;
          while {{AnimationEffect/getTiming()}} can return
          the string <code>auto</code>,
          {{AnimationEffect/getComputedTiming()}} must return
          a number corresponding to
          the calculated value of the [=iteration duration=]
          as defined in the description of
          the {{EffectTiming/duration}} member of the {{EffectTiming}} interface.

          In this level of the specification, that simply means that an
          <code>auto</code> value is replaced by zero.

      * {{EffectTiming/fill}} &ndash;
          likewise, while {{AnimationEffect/getTiming()}} can return
          the string <code>auto</code>,
          {{AnimationEffect/getComputedTiming()}} must return
          the specific {{FillMode}} used for timing calculations
          as defined in the description of
          the {{EffectTiming/fill}} member of the {{EffectTiming}} interface.

          In this level of the specification,
          that simply means that an <code>auto</code> value is replaced
          by the <code>none</code> {{FillMode}}.

      Note: It is likely that other timing members
      could be extended in future to include <code>auto</code>-like values.
      When performing timing calculations,
      authors are encouraged
      to use {{AnimationEffect/getComputedTiming()}} where possible
      to avoid incompatibility
      should the range or type of allowed specified values be changed.

      In addition to possible differences in the values returned,
      compared to {{AnimationEffect/getTiming()}},
      {{AnimationEffect/getComputedTiming()}} returns
      additional timing information
      as defined by the {{ComputedEffectTiming}} dictionary.

  : <dfn>updateTiming(<var ignore>timing</var>)</dfn>
  ::
      Updates the specified timing properties of this [=animation effect=]
      by performing the procedure to
      [=update the timing properties of an animation effect=]
      passing the {{AnimationEffect/updateTiming(timing)/timing}} parameter
      as |input|.

      <div dfn-type=argument class=parameters
           dfn-for="AnimationEffect/updateTiming(timing)">

      : <dfn lt="timing">optional {{OptionalEffectTiming}} timing</dfn>
      ::
          The timing properties to update.
          The timing properties corresponding to any members
          that do not [=map/exist=] on {{AnimationEffect/updateTiming(timing)/timing}}
          will <em>not</em> be modified.

      </div>

  </div>

  Issue(2082): The <code>remove()</code> method can be used to remove an effect
  from either its parent group or animation.
  Should we keep it in level 1 and define it simply
  as removing the animation effect from its animation?

### The {{EffectTiming}} and {{OptionalEffectTiming}} dictionaries ### {#the-effecttiming-dictionaries}

  The <dfn dictionary>EffectTiming</dfn> dictionary represents
  the timing properties of an {{AnimationEffect}}.

  The <dfn dictionary>OptionalEffectTiming</dfn> dictionary
  is a variant of the {{EffectTiming}} dictionary
  that allows some members to not [=map/exist=].
  This is used by the {{AnimationEffect/updateTiming()}} method
  of the {{AnimationEffect}} interface
  to perform a delta update to the timing properties of an [=animation effect=].

  <xmp class=idl>
    dictionary EffectTiming {
      double                             delay = 0;
      double                             endDelay = 0;
      FillMode                           fill = "auto";
      double                             iterationStart = 0.0;
      unrestricted double                iterations = 1.0;
      (unrestricted double or DOMString) duration = "auto";
      PlaybackDirection                  direction = "normal";
      DOMString                          easing = "linear";
    };

    dictionary OptionalEffectTiming {
      double                             delay;
      double                             endDelay;
      FillMode                           fill;
      double                             iterationStart;
      unrestricted double                iterations;
      (unrestricted double or DOMString) duration;
      PlaybackDirection                  direction;
      DOMString                          easing;
    };
  </xmp>

  <div dfn-type=dict-member class=members
      dfn-for="EffectTiming"> <!-- XXX this should be "EffectTiming,OptionalEffectTiming" -->

  : <dfn>delay</dfn>
  ::
      The [=start delay=],
      which represents the number of milliseconds
      from the [=start time=] of the associated [=animation=]
      to the start of the [=active interval=].

  : <dfn>endDelay</dfn>
  ::
      The [=end delay=],
      which represents the number of milliseconds
      from the end of an [=animation effect=]’s [=active interval=]
      until its [=animation effect/end time=].

  : <dfn>fill</dfn>
  ::
      The [=fill mode=],
      which defines the behavior of the [=animation effect=]
      outside its [=active interval=].

      When performing timing calculations
      the special string value <code>auto</code> is expanded
      to one of the [=fill modes=] recognized by the timing model
      as follows:

      <dl class=switch>

      : If the [=animation effect=] to which the fill mode is being applied
          is a [=keyframe effect=],
      ::
          Use [=fill mode/none=] as the [=fill mode=].

      : Otherwise,
      ::  Use [=fill mode/both=] as the [=fill mode=].

      </dl>

      Advisement: As described in [[#fill-behavior]],
      authors are discouraged from using indefinitely filling animations.

  : <dfn>iterationStart</dfn>
  ::
      The [=animation effect=]’s [=iteration start=] property,
      which is a finite real number greater than or equal to zero
      representing the [=iteration index=] at which the [=animation effect=] begins
      and its progress through that iteration.

      For example, a value of 0.5 indicates that
      the animation effect begins halfway through its first iteration.
      A value of 1.2 indicates the animation effect begins
      20% of the way through its second iteration.

      <div class=note>
        Note that the value of {{EffectTiming/iterations}}
        is effectively <em>added</em> to the {{EffectTiming/iterationStart}}
        such that an animation effect with
        an {{EffectTiming/iterationStart}} of "0.5"
        and {{EffectTiming/iterations}} of "2"
        will still repeat twice.
        However it will begin and end halfway through
        its [=iteration interval=].

        {{EffectTiming/iterationStart}} values greater than or equal to 1
        are typically only useful in combination with an animation effect
        that has an [=iteration composite operation=] of
        <span class="enum-value">accumulate</span>
        or when the [=current iteration index=] is otherwise significant.
      </div>

  : <dfn>iterations</dfn>
  ::
      The [=animation effect=]’s [=iteration count=] property
      which is a real number greater than or equal to zero
      (including positive infinity)
      representing the number of times to the animation effect repeats.

      This can be set to <code class=esvalue>+Infinity</code>
      to cause the [=animation effect=] to repeat forever
      (unless the duration of the effect is zero,
      in which case it will finish immediately).

  : <dfn>duration</dfn>
  ::
      The [=iteration duration=],
      which is a real number greater than or equal to zero
      (including positive infinity)
      representing the time taken to complete
      a single iteration of the [=animation effect=].

      In this level of this specification,
      the string value <code>auto</code>
      is treated as the value zero
      for the purpose of timing model calculations
      and for the result of the {{EffectTiming/duration}} member
      returned from {{AnimationEffect/getComputedTiming()}}.
      If the author specifies the <code>auto</code> value,
      user agents must, however, return <code>auto</code>
      for the {{EffectTiming/duration}} member
      returned from {{AnimationEffect/getTiming()}}.

      Note: This is a forwards-compatibility measure
      since a future level of this specification
      is expected to introduce group effects
      where the <code>auto</code> value expands
      to include the duration of the child effects.

  : <dfn>direction</dfn>
  ::
      The [=playback direction=] of the [=animation effect=],
      which defines whether playback
      proceeds forwards, backwards, or alternates on each iteration.

  : <dfn>easing</dfn>
  ::
      The [=easing function=] used to scale the time
      to produce easing effects.

      The syntax of the string is defined
      by the <<easing-function>> production [[!CSS-EASING-1]].

  </div>

### The {{FillMode}} enumeration ### {#the-fillmode-enumeration}

  <xmp class=idl>
    enum FillMode { "none", "forwards", "backwards", "both", "auto" };
  </xmp>

  Represents an [=animation effect=]’s [=fill mode=].

  <dl dfn-type=enum-value
      dfn-for="FillMode,PlaybackDirection">
  : <dfn>none</dfn>
  ::  No fill. ([=Fill mode=] [=fill mode/none=].)
  : <dfn>forwards</dfn>
  ::  Fill [=fill mode/forwards=].
  : <dfn>backwards</dfn>
  ::  Fill [=fill mode/backwards=].
  : <dfn>both</dfn>
  ::  Fill [=fill mode/both=] backwards and forwards.
  : <dfn>auto</dfn>
  ::  No fill.
      In a subsequent level of this specification, this may produce
      different behavior for other types of [=animation effects=].

  </dl>

### The {{PlaybackDirection}} enumeration ### {#the-playbackdirection-enumeration}

  <xmp class=idl>
    enum PlaybackDirection { "normal", "reverse", "alternate", "alternate-reverse" };
  </xmp>


  <dl dfn-type=enum-value
      dfn-for="PlaybackDirection">

  : <dfn>normal</dfn>
  ::
      All iterations are played as specified.

  : <dfn>reverse</dfn>
  ::
      All iterations are played in the reverse direction
      from the order they are specified.

  : <dfn>alternate</dfn>
  ::
      Even iterations are played as specified,
      odd iterations are played in the reverse direction
      from the order they are specified.

  : <dfn>alternate-reverse</dfn>
  ::
      Even iterations are played in the reverse direction
      from the order they are specified,
      odd iterations are played as specified.

  </dl>

### Updating the timing of an {{AnimationEffect}} ### {#updating-animationeffect-timing}

  To <dfn>update the timing properties of an animation effect</dfn>, |effect|,
  from an {{EffectTiming}} or {{OptionalEffectTiming}} object, |input|,
  perform the following steps:

  1. If the {{EffectTiming/iterationStart}} member of |input|
      [=map/exists=] and is less than zero,
      [=throw=] a {{TypeError}} and abort this procedure.

      Note: The reason for using a {{TypeError}} rather than a {{RangeError}}
      is to mirror the behavior of WebIDL's [=[EnforceRange]=] annotation
      should that annotation be able to be used with floating-point values
      in the future.

  1. If the {{EffectTiming/iterations}} member of |input| [=map/exists=],
      and is less than zero or is the value <code class=esvalue>NaN</code>,
      [=throw=] a {{TypeError}} and abort this procedure.

  1. If the {{EffectTiming/duration}} member of |input| [=map/exists=],
      and is less than zero or is the value <code class=esvalue>NaN</code>,
      [=throw=] a {{TypeError}} and abort this procedure.

  1. If the {{EffectTiming/easing}} member of |input| [=map/exists=]
      but cannot be parsed using the <<easing-function>> production
      [[!CSS-EASING-1]],
      [=throw=] a {{TypeError}} and abort this procedure.

  1. Assign each member that [=map/exists=] in |input|
      to the corresponding timing property of |effect| as follows:

      * {{EffectTiming/delay}} &rarr; [=start delay=]
      * {{EffectTiming/endDelay}} &rarr; [=end delay=]
      * {{EffectTiming/fill}} &rarr; [=fill mode=]
      * {{EffectTiming/iterationStart}} &rarr; [=iteration start=]
      * {{EffectTiming/iterations}} &rarr; [=iteration count=]
      * {{EffectTiming/duration}} &rarr; [=iteration duration=]
      * {{EffectTiming/direction}} &rarr; [=playback direction=]
      * {{EffectTiming/easing}} &rarr; [=easing function=]

### The <code>ComputedEffectTiming</code> dictionary ### {#the-computedeffecttiming-dictionary}

  Timing properties calculated by the timing model
  are exposed using {{ComputedEffectTiming}} dictionary objects.

  <xmp class=idl>
    dictionary ComputedEffectTiming : EffectTiming {
      unrestricted double  endTime;
      unrestricted double  activeDuration;
      double?              localTime;
      double?              progress;
      unrestricted double? currentIteration;
    };
  </xmp>

  <div dfn-type=dict-member class=members
       dfn-for="ComputedEffectTiming">

  : <dfn>endTime</dfn>
  ::
      The [=animation effect/end time=] of the [=animation effect=]
      expressed in milliseconds since zero [=local time=]
      (that is, since the associated [=animation=]’s [=start time=]
       if this [=animation effect=] is [=associated with an animation=]).
      This corresponds to
      the end of the [=animation effect=]’s [=active interval=]
      plus any [=end delay=].

  : <dfn>activeDuration</dfn>
  ::
      The [=active duration=] of this [=animation effect=].

  : <dfn>localTime</dfn>
  ::
      The [=local time=] of this [=animation effect=].

      This will be `null` if this [=animation effect=]
      is not [=associated with an animation=].

  : <dfn>progress</dfn>
  ::
      The current [=iteration progress=] of this [=animation effect=].

  : <dfn>currentIteration</dfn>
  ::
      The [=current iteration index=]
      beginning with zero for the first iteration.

      In most cases this will be a (positive) integer.
      However, for a zero-duration animation
      that repeats infinite times,
      the value will be positive <code class=esvalue>Infinity</code>.

      As with [=unresolved=] times,
      an unresolved [=iteration index=] is represented
      by a `null` value.

  </div>

The {{KeyframeEffect}} interface {#the-keyframeeffect-interface}
--------------------------------

  [=Keyframe effects=] are represented by
  the <dfn interface>KeyframeEffect</dfn> interface.

  <xmp class=idl>
    [Exposed=Window]
    interface KeyframeEffect : AnimationEffect {
      constructor(Element?       target,
                  object?        keyframes,
                  optional (unrestricted double or KeyframeEffectOptions) options = {});
      constructor(KeyframeEffect source);
      attribute Element?           target;
      attribute CSSOMString?       pseudoElement;
      attribute CompositeOperation composite;
      sequence<object> getKeyframes();
      undefined        setKeyframes(object? keyframes);
    };
  </xmp>

  <wpt>
    animation-model/keyframe-effects/effect-in-removed-iframe-crash.html
  </wpt>

  <div dfn-type=constructor class=constructors
       dfn-for="KeyframeEffect">

  : <dfn lt="KeyframeEffect(target, keyframes, options)">
      KeyframeEffect (|target|, |keyframes|, |options|)</dfn>
  ::
      Creates a new {{KeyframeEffect}} object using the following procedure:

      1. Create a new {{KeyframeEffect}} object, |effect|.

      1. Set the [=target element=] of |effect| to |target|.

      1. Set the [=target pseudo-selector=] to the result
          corresponding to the first matching condition below:

          <dl class=switch>
          : If |options| is a {{KeyframeEffectOptions}} object
              with a {{KeyframeEffectOptions/pseudoElement}} property,
          ::
              Set the [=target pseudo-selector=] to the value of
              the {{KeyframeEffectOptions/pseudoElement}} property.

              When assigning this property,
              the error-handling defined for
              the {{KeyframeEffect/pseudoElement}} setter on the interface
              is applied.
              If the setter requires an exception to be thrown,
              this procedure must throw the same exception
              and abort all further steps.

          : Otherwise,
          ::
              Set the [=target pseudo-selector=] to `null`.

          </dl>

      1. Let |timing input| be the result
          corresponding to the first matching condition below:

          : If |options| is a {{KeyframeEffectOptions}} object,
          ::
              Let |timing input| be |options|.

          : Otherwise (if |options| is a `double`),
          ::
              Let |timing input| be a new {{EffectTiming}} object
              with all members set to their default values
              and {{EffectTiming/duration}} set to |options|.

      1. Call the procedure to
          [=update the timing properties of an animation effect=] of |effect|
          from |timing input|.

          If that procedure causes an exception to be thrown,
          propagate the exception and abort this procedure.

      1. If |options| is a {{KeyframeEffectOptions}} object,
          assign the {{KeyframeEffect/composite}} property of |effect|
          to the corresponding value from |options|.

          When assigning this property,
          the error-handling defined for
          the corresponding setter on the {{KeyframeEffect}} interface
          is applied.
          If the setter requires an exception to be thrown
          for the value specified by |options|,
          this procedure must [=throw=] the same exception
          and abort all further steps.

      1. Initialize the set of [=keyframes=]
          by performing the procedure
          defined for {{KeyframeEffect/setKeyframes()}}
          passing |keyframes| as the input.

      <div dfn-type=argument class=parameters
           dfn-for="KeyframeEffect/KeyframeEffect(target, keyframes, options)">

      : <dfn lt="target">{{Element}}? target</dfn>
      ::
          The [=target element=].
          This may be `null`
          for animations that do not target a specific element.

      : <dfn lt="keyframes">object? keyframes</dfn>
      ::
          The set of [=keyframes=] to use.
          The format and processing of this argument
          is defined in [[#processing-a-keyframes-argument]].

      : <dfn lt="options">optional {{KeyframeEffectOptions}} options</dfn>
      ::
          Either a number specifying the [=iteration duration=] of the effect,
          or a collection of properties specifying
          the timing and behavior of the effect.

      Examples of the usage of this constructor are given in
      [[#creating-a-new-keyframeeffect-object]].

  : <dfn lt="KeyframeEffect(source)">KeyframeEffect (source)</dfn>
  ::
      Creates a new {{KeyframeEffect}} object
      with the same properties as {{KeyframeEffect/KeyframeEffect(source)/source}}
      using the following procedure:

      1. Create a new {{KeyframeEffect}} object, |effect|.

      1. Set the following properties of |effect|
          using the corresponding values of |source|:

          * [=effect target=],
          * [=keyframes=],
          * [=composite operation=],
            and
          * all specified timing properties:
              * [=start delay=],
              * [=end delay=],
              * [=fill mode=],
              * [=iteration start=],
              * [=iteration count=],
              * [=iteration duration=],
              * [=playback direction=],
                and
              * [=easing function=].

          Note: Unlike
          the {{KeyframeEffect(target, keyframes, options)}} constructor,
          we do not need to re-throw exceptions
          since the timing properties specified on |source|
          can be assumed to be valid.

      <div dfn-type=argument class=parameters
           dfn-for="KeyframeEffect/KeyframeEffect(source)">

      : <dfn lt="source">{{KeyframeEffect}} source</dfn>
      ::
          The [=keyframe effect=] from which to copy the properties
          that define the new [=keyframe effect=].

      </div>

  </div>

  <div dfn-type=attribute class=attributes
       dfn-for="KeyframeEffect">

  : <dfn>target</dfn>
  ::
      The [=target element=] being animated by this object
      (either the [=effect target=] if it is an {{Element}}
       or its [=originating element=] if it is a pseudo-element).
      This may be `null` for animations
      that do not target a specific element
      such as an animation that produces a sound using an audio API.

  : <dfn>pseudoElement</dfn>
  ::
      The [=target pseudo-selector=].
      `null` if this effect has no [=effect target=]
      or if the [=effect target=] is an element (i.e. not a pseudo-element).
      When the [=effect target=] is a pseudo-element,
      this specifies the pseudo-element selector (e.g. `::before`).

      On setting,
      sets the [=target pseudo-selector=] of the [=animation effect=]
      to the result of <dfn>pseudo-element parsing</dfn> on the provided value,
      defined as the following:

        1. Given the value |value|, perform the following steps:
          1. If |value| is not `null`
               and is an [=invalid selector|invalid=] <<pseudo-element-selector>>,

              1. [=Throw=] a {{DOMException}}
                  with error name "{{SyntaxError}}".

              1. Abort.

                  Note: In effect, this means that if the result of this algorithm is
                  used to set a variable, then that variable remains unchanged.

               Note: Invalid in this context follows the definition of
               an [=invalid selector=] defined in [[!SELECTORS-4]]
               such that syntactically invalid pseudo-elements
               as well as pseudo-elements for which the user agent
               has no usable level of support
               are both deemed invalid.

          1. If |value| is one of the legacy Selectors Level 2 single-colon selectors
              (':before', ':after', ':first-letter', or ':first-line'), then
              return the equivalent two-colon selector (e.g. '::before').

          1. Otherwise, return |value|.

  : <dfn>composite</dfn>
  ::
      The [=composite operation=] used
      to composite this [=keyframe effect=] with the [=effect stack=],
      as specified by one of the {{CompositeOperation}} enumeration values.

      On setting,
      sets the [=composite operation=] property of this [=animation effect=]
      to the provided value.

  </div>

  <div dfn-type=method class=methods
       dfn-for="KeyframeEffect">

  : <dfn lt="getKeyframes()">sequence&lt;object&gt; getKeyframes()</dfn>
  ::
      Returns the keyframes that make up this effect
      along with their [=computed keyframe offsets=].

      <div class=informative-bg>
        <em>This section is non-normative</em>

        The result of this method is a sequence of objects
        of the following format:

        <pre highlight=idl>
          dictionary ComputedKeyframe {
            // ... property-value pairs ...
            // i.e. DOMString propertyName
            double?                  offset = null;
            double                   computedOffset;
            DOMString                easing = "linear";
            CompositeOperationOrAuto composite = "auto";
          };
        </pre>

        The meaning and values of each member is as follows:

        : <code>offset</code>
        ::
            The [=keyframe offset=] of the [=keyframe=]
            specified as a number between 0.0 and 1.0 inclusive,
            or `null`.

            This will be `null` if the [=keyframe=]
            is to be automatically spaced between adjacent keyframes.

        : <code>computedOffset</code>
        ::
            The [=computed keyframe offset=] for this [=keyframe=]
            calculated as part of running
            the [=compute missing keyframe offsets=] procedure.

            Unlike the <code>offset</code> member,
            the <code>computedOffset</code> is never `null`.

        : <code>easing</code>
        ::
            The [=easing function=] used to transform the progress of time
            from this keyframe until the next keyframe in the series.

        : <code>composite</code>
        ::
            The [=keyframe-specific composite operation=] used
            to combine the values specified in this keyframe
            with the [=underlying value=].

            This member will be {{CompositeOperationOrAuto/auto}}
            if the [=composite operation=] specified on the [=keyframe effect=]
            is being used.

      </div>

      Since [=keyframes=] are represented
      by a partially open-ended dictionary type
      that is not currently able to be expressed with WebIDL,
      the procedure used to prepare the result of this method
      is defined in prose below:

      1. Let |result| be an empty sequence of objects.
      1. Let |keyframes| be one of the following:

          : If this [=keyframe effect=] is associated with a {{CSSAnimation}},
              and its [=keyframes=] have not been replaced
              by a successful call to {{KeyframeEffect/setKeyframes()}},
          ::
              the [=computed keyframes=] for this [=keyframe effect=].

          : Otherwise,
          ::
              the result of applying the procedure
              [=compute missing keyframe offsets=]
              to the [=keyframes=] for this [=keyframe effect=].

          Note: We return [=computed keyframes=] for CSS Animations
                because not all keyframes specified in CSS
                can be represented by a dictionary.

      1. For each |keyframe| in |keyframes|
          perform the following steps:

          1. Initialize a dictionary object, |output keyframe|,
              using the following definition:

              <xmp class=idl dfn-for="">
               dictionary BaseComputedKeyframe {
                   double?                  offset = null;
                   double                   computedOffset;
                   DOMString                easing = "linear";
                   CompositeOperationOrAuto composite = "auto";
              };
              </xmp>

          1. Set the
              {{BaseComputedKeyframe/offset}},
              {{BaseComputedKeyframe/computedOffset}},
              {{BaseComputedKeyframe/easing}},
              and
              {{BaseComputedKeyframe/composite}}
              members of |output keyframe|
              to the respective
              [=keyframe offset=],
              [=computed keyframe offset=],
              keyframe-specific [=easing function=],
              and [=keyframe-specific composite operation=]
              values of |keyframe|.

          1. For each animation property-value pair |declaration| in |keyframe|,
              perform the following steps:

              1. Let |property name| be the result of applying the
                  [=animation property name to IDL attribute name=] algorithm
                  to the property name of |declaration|.

              1. Let |IDL value| be the result
                  of serializing the property value of |declaration|
                  by passing |declaration| to
                  the algorithm to [=serialize a CSS value=] [[!CSSOM]].

              1. Let |value| be the result of [=DOMString to es|converting=]
                  |IDL value| to an ECMAScript String value.

              1. Call the <a>\[[DefineOwnProperty]]</a> internal method
                  on |output keyframe|
                  with property name |property name|,
                  Property Descriptor {
                    \[[Writable]]: <span class=esvalue>true</span>,
                    \[[Enumerable]]: <span class=esvalue>true</span>,
                    \[[Configurable]]: <span class=esvalue>true</span>,
                    \[[Value]]: |value|
                  }
                  and Boolean flag <span class=esvalue>false</span>.

          1. Append |output keyframe| to |result|.

      1. Return |result|.

  : <dfn lt="setKeyframes(keyframes)">void setKeyframes(object? keyframes)</dfn>
  ::
      Replaces the set of [=keyframes=] that make up this effect.

      <div dfn-type=argument class=parameters
        for="KeyframeEffect/setKeyframes">

      : <dfn lt="keyframes">object? keyframes</dfn>
      ::
          A series of keyframes whose format and processing
          is defined by [[#processing-a-keyframes-argument]].

          This effect's set of [=keyframes=] is replaced with the result
          of performing the procedure to [=process a keyframes argument=].
          If that procedure throws an exception,
          this effect's [=keyframes=] are not modified.

      </div>

  </div>

### Creating a new <code>KeyframeEffect</code> object ### {#creating-a-new-keyframeeffect-object}

<div class=informative-bg>
<em>This section is non-normative</em>

  The {{KeyframeEffect(target, keyframes, options)|KeyframeEffect}} constructor
  offers a number of approaches to creating new {{KeyframeEffect}} objects.

  At its simplest, a {{KeyframeEffect}} object that changes
  the "left" property of <code>elem</code> to 100px over three seconds
  can be constructed as follows:

  <div class=example>
    <pre highlight=javascript>
      var effect = new KeyframeEffect(elem, { left: '100px' }, 3000);
    </pre>
  </div>

  The second parameter, representing the list of keyframes,
  may specify multiple properties.
  (See [[#processing-a-keyframes-argument]].)

  <div class=example>
    <pre highlight=javascript>
      // Specify multiple properties at once
      var effectA = new KeyframeEffect(elem, { left: '100px', top: '300px' }, 3000);

      // Specify multiple keyframes
      var effectB = new KeyframeEffect(elem, [ { left: '100px' }, { left: '300px' } ], 3000);
    </pre>
  </div>

  The third parameter, representing the animation's timing,
  may simply be a number representing
  the [=iteration duration=] in milliseconds as above,
  or, to specify further timing properties such as the [=start delay=],
  an {{EffectTiming}} object can be used,
  as follows:

  <div class=example>
    <pre highlight=javascript>
      var effect =
        new KeyframeEffect(elem, { left: '100px' }, { duration: 3000, delay: 2000 });
    </pre>
  </div>

  If the duration is not specified, a value of zero is used.
  It is possible to create an animation
  that simply sets a property without any interpolation
  as follows:

  <div class=example>
    <pre highlight=javascript>
      var effect =
        new KeyframeEffect(elem, { visibility: 'hidden' }, { fill: 'forwards' });
    </pre>
  </div>

  As described in [[#fill-behavior]] however,
  using indefinitely filling animations in this way is discouraged.

  Having created a {{KeyframeEffect}},
  it can be played by adding it to an {{Animation}}
  and then playing that animation.
  For simple effects, however,
  the <a href="#extensions-to-the-element-interface"><code>Element.animate</code></a>
  shortcut is more convenient
  since it performs these steps automatically.
  For example,

  <div class=example>
    <pre highlight=javascript>
      elem.animate({ left: '100px' }, 3000);
    </pre>
  </div>
</div>

### Property names and IDL names ### {#property-name-conversion}

  <div algorithm>
    The <dfn>animation property name to IDL attribute name</dfn> algorithm
    for |property|
    is as follows:

    1. If |property| follows the <<custom-property-name>> production,
        return |property|.

    1. If |property| refers to the CSS 'float' property,
        return the string "cssFloat".

    1. If |property| refers to the CSS 'offset' property,
        return the string "cssOffset".

    1. Otherwise, return the result of applying
        the [=CSS property to IDL attribute=] algorithm [[!CSSOM]]
        to |property|.
  </div>

  <div algorithm>
    The <dfn>IDL attribute name to animation property name</dfn> algorithm
    for |attribute|
    is as follows:

    1. If |attribute| conforms to the <<custom-property-name>> production,
        return |attribute|.

    1. If |attribute| is the string "cssFloat", then return
        an animation property representing the CSS 'float' property.

    1. If |attribute| is the string "cssOffset", then return
        an animation property representing the CSS 'offset' property.

    1.  Otherwise, return the result of applying
        the [=IDL attribute to CSS property=] algorithm [[!CSSOM]]
        to |attribute|.
  </div>

### Processing a <code>keyframes</code> argument ### {#processing-a-keyframes-argument}

<div class=informative-bg>
<em>This section is non-normative</em>

  The following methods all accept a set of keyframes as an argument:

  * the {{KeyframeEffect(target, keyframes, options)}} constructor,
  * the {{KeyframeEffect/setKeyframes()}} method
      on the {{KeyframeEffect}} interface,
  * the {{Animatable/animate()}} method
      of the {{Animatable}} interface mixin.

  This argument can be specified in the one of two forms as illustrated below:

  <div class=example>
    <pre highlight=javascript>
      // The following two expressions produce the same result:
      elem.animate([ { color: 'blue' },
                     { color: 'green' },
                     { color: 'red' },
                     { color: 'yellow' } ], 2000);
      elem.animate({ color: [ 'blue', 'green', 'red', 'yellow' ] }, 2000);

      // Likewise, for a multi-property animation, the following two
      // expressions are equivalent:
      elem.animate([ { color: 'blue', left: '0px' },
                     { color: 'green', left: '-20px' },
                     { color: 'red', left: '100px' },
                     { color: 'yellow', left: '50px'} ], 2000);
      elem.animate({ color: [ 'blue', 'green', 'red', 'yellow' ],
                     left: [ '0px', '-20px', '100px', '50px' ] }, 2000);

      // Incidentally, the following three expressions are all equivalent:
      elem.animate([ { color: 'red' } ], 1000);
      elem.animate({ color: [ 'red' ] }, 1000);
      elem.animate({ color: 'red' }, 1000);
    </pre>
  </div>

  The first form (the array-form)
  consists of an array of keyframes
  where each keyframe may specify at most one value per animation property.
  The second form (the object-form)
  consists of an object
  where each animation property may specify
  a single animation value or an array of animation values.

  The first array-form is the canonical form,
  and is the form returned by the {{KeyframeEffect/getKeyframes()}} method.

  [=Keyframe offsets=] can be specified using either form as illustrated below:

  <div class=example>
    <pre highlight=javascript>
      // The keyframes without offsets will automatically have offsets computed
      // as 0 for the first keyframe, 0.65 for the middle keyframe, and 1 for the
      // final keyframe.
      elem.animate([ { color: 'blue' },
                     { color: 'green', offset: 0.5 },
                     { color: 'red' },
                     { color: 'yellow', offset: 0.8 },
                     { color: 'pink' } ], 2000);

      // The following produces the same result. Note that it is not necessary to
      // specify the last value: it will automatically be treated as 'null' and then
      // the automatic assignment will apply as with the previous case.
      elem.animate({ color: [ 'blue', 'green', 'red', 'yellow', 'pink' ],
                     offset: [ null, 0.5, null, 0.8 ] }, 2000);
    </pre>
  </div>

  Likewise [=easing functions=] and [=keyframe-specific composite operations=]
  may be specified in either form.
  The array-form allows specifying different values for each [=keyframe=]
  whilst for the object-form,
  the list of values will be repeated as needed
  until each keyframe has been assigned a value.

  <div class=example>
    <pre highlight=javascript>
      // Since easing functions apply _between_ keyframes, even if we specify a
      // an easing function on the last keyframe it will be ignored.
      elem.animate([ { color: 'blue', easing: 'ease-in' },
                     { color: 'green', easing: 'ease-out' },
                     { color: 'yellow' } ], 2000);

      // The following produces the same result.
      elem.animate({ color: [ 'blue', 'green', 'yellow' ],
                     easing: [ 'ease-in', 'ease-out' ] }, 2000);

      // The repeating behavior makes assigning the same value to all keyframes
      // simple:
      elem.animate({ color: [ 'blue', 'green', 'yellow' ],
                     easing: 'ease-in-out' }, 2000);
    </pre>
  </div>

  Note that the <code>easing</code> property in either form
  sets the <em>keyframe-specific [=easing function=]</em>.
  This is independent from the [=easing function=]
  that applies to the entire [=iteration duration=] of the [=keyframe effect=]
  as specified using a {{KeyframeEffectOptions}} object
  (or {{KeyframeAnimationOptions}} object
   when using the {{Animatable/animate()}} method
   of the {{Animatable}} interface mixin).

  In the following example, the two statements produce different results.

  <div class=example>
    <pre highlight=javascript>
      // Here, 'ease-in-out' is applied between each color value.
      elem.animate({ color: [ 'blue', 'green', 'yellow' ],
                     easing: 'ease-in-out' }, 2000);

      // However, in this case, 'ease-in-out' is applied across the whole span
      // of the animation, that is from 'blue' to 'yellow'.
      elem.animate({ color: [ 'blue', 'green', 'yellow' ] },
                   { duration: 2000, easing: 'ease-in-out' });
    </pre>
  </div>

  The type of the <code>keyframes</code> argument cannot be expressed in WebIDL
  since it relies on a partially-open dictionary type.

  Conceptually, the type of this argument
  is equivalent to the following WebIDL-like definition:

  <xmp highlight=idl>
    dictionary Keyframe {
      // ... property-value pairs ...
      // i.e. DOMString propertyName
      double?                   offset = null;
      DOMString                 easing = "linear";
      CompositeOperationOrAuto  composite = "auto";
    };

    dictionary PropertyIndexedKeyframes {
      // ... property-value and property-valuelist pairs ...
      // i.e. (DOMString or sequence<DOMString>) propertyName
      (double? or sequence<double?>)                         offset = [];
      (DOMString or sequence<DOMString>)                     easing = [];
      (CompositeOperationOrAuto or sequence<CompositeOperationOrAuto>) composite = [];
    };

    typedef (sequence<Keyframe?> or PropertyIndexedKeyframes) KeyframeArgument;
  </xmp>

  The meaning and allowed values of each argument is as follows:

  : <code>offset</code>
  ::
      The [=keyframe offset=] of the [=keyframe=]
      specified as a number between 0.0 and 1.0 inclusive
      or `null`.

      A `null` value indicates that the [=keyframe=]
      should be automatically spaced between adjacent keyframes.

      Specifying an offset outside the range [0.0, 1.0] will cause
      a {{TypeError}} to be thrown.

      Keyframes that specify an offset must be provided
      in increasing order of offset.
      Adjacent and equal offsets, however, are permitted.

  : <code>easing</code>
  ::
      The [=easing function=] used to transform the progress of time
      from this keyframe until the next keyframe in the series.

      The syntax and error-handling associated with parsing this string
      is identical to that defined for the {{EffectTiming/easing}} attribute
      of the {{EffectTiming}} interface.

  : <code>composite</code>
  ::
      The [=keyframe-specific composite operation=] used
      to combine the values specified in this keyframe
      with the [=underlying value=].

      If {{CompositeOperationOrAuto/auto}},
      the [=composite operation=] specified on the [=keyframe effect=]
      will be used.

  Since this type cannot be expressed in WebIDL,
  its processing is defined in prose following.
</div>

  For each method that takes a <code>keyframes</code> argument,
  the procedure to [=process a keyframes argument=] is run on the input
  and the result of that procedure is retained.

  <wpt>
    animation-model/keyframe-effects/keyframe-exceptions.html
  </wpt>

  First we define two supporting definitions:

  <div algorithm>
    The instruction <dfn>check the completion record</dfn> of |result|,
    where |result| is a [=completion record specification type|completion record=]
    from calling an ECMAScript operation,
    is equivalent to the following steps:

    1. If |result| is
        an [=completion record specification type|abrupt completion=],
        [=throw=] the exception contained in the \[[value]] field of |result|
        and abort the procedure.

        Issue: What should we do if the \[[type]] is
        <span class=esvalue>break</span>,
        <span class=esvalue>continue</span>, or
        <span class=esvalue>return</span>?
        Can it be?

    1. Replace |result| with
        the value contained in the \[[value]] field of |result|.
  </div>

  <div algorithm>
    The procedure to <dfn>process a keyframe-like object</dfn>
    takes two arguments:

    * an ECMAScript object, |keyframe input|, and
    * an |allow lists| boolean flag

    and returns a map from either property names to DOMString values
    if |allow lists| is false,
    or from property names to sequences of DOMString values otherwise,
    using the following procedure:

    1. Run the procedure to
        [=es to dictionary|convert an ECMAScript value to a dictionary type=] [[!WEBIDL]]
        with |keyframe input| as the ECMAScript value,
        and the dictionary type depending on the value of the |allow lists| flag
        as follows:

        <div class=switch>
        : If |allow lists| is true,
        ::
            Use the following dictionary type:

            <xmp class=idl>
              dictionary BasePropertyIndexedKeyframe {
                (double? or sequence<double?>)                         offset = [];
                (DOMString or sequence<DOMString>)                     easing = [];
                (CompositeOperationOrAuto or sequence<CompositeOperationOrAuto>) composite = [];
              };
            </xmp>

        : Otherwise,
        ::
            Use the following dictionary type:

            <xmp class=idl>
              dictionary BaseKeyframe {
                double?                  offset = null;
                DOMString                easing = "linear";
                CompositeOperationOrAuto composite = "auto";
              };
            </xmp>

        </div>

        Store the result of this procedure as |keyframe output|.

    1. Build up a list of |animatable properties| as follows:

        1. Let |animatable properties| be a list of property names
            (including shorthand properties
             that have longhand sub-properties that are animatable)
            that can be animated by the UA.

        1. Convert each property name in |animatable properties|
            to the equivalent IDL attribute by applying the
            [=animation property name to IDL attribute name=] algorithm.

    1. Let |input properties| be
        the result of calling the [=EnumerableOwnNames=] operation
        with |keyframe input| as the object.

    1. Make up a new list |animation properties|
        that consists of all of the properties that are in <em>both</em>
        |input properties| and |animatable properties|, <em>or</em>
        which are in |input properties| and
        conform to the <<custom-property-name>> production.

    1. Sort |animation properties| in ascending order
        by the Unicode codepoints that define each property name.

    1. For each |property name| in |animation properties|:

        1. Let |raw value| be the result of calling
            the [=[[Get]]=] internal method on |keyframe input|,
            with |property name| as the property key
            and |keyframe input| as the receiver.

        1. [=Check the completion record=] of |raw value|.

        1. Convert |raw value|
            to a DOMString or to a sequence of DOMStrings |property values|
            as follows:

            <div class=switch>
            : If |allow lists| is true,
            ::
                Let |property values| be the result of converting
                |raw value| to IDL type
                <code>(DOMString or sequence&lt;DOMString&gt;)</code>
                using the
                [=convert ECMAScript to IDL value|procedures defined for converting
                an ECMAScript value to an IDL value=]
                [[!WEBIDL]].

                If |property values| is a single DOMString,
                replace |property values|
                with a sequence of DOMStrings
                with the original value of |property values|
                as the only element.

            : Otherwise,
            ::
                Let |property values| be the result of converting
                |raw value| to a DOMString
                using the
                [=es to DOMString|procedure for converting
                an ECMAScript value to a DOMString=] [[!WEBIDL]].

            </div>

        1. Calculate the |normalized property name|
            as the result of applying the
            [=IDL attribute name to animation property name=] algorithm
            to |property name|.

        1. Add a property to |keyframe output|
            with |normalized property name| as the property name,
            and |property values| as the property value.

    1. Return |keyframe output|.
  </div>

  <div algorithm>
    The procedure to <dfn>process a keyframes argument</dfn>
    takes a [=nullable=] ECMAScript object, |object|, as input,
    and returns a sequence of keyframes using the following procedure:

    1. If |object| is `null`,
        return an empty sequence of keyframes.

    1. Let |processed keyframes| be
        an empty sequence of [=keyframes=].

    1. Let |method| be the result of
        [=GetMethod=](|object|, <a lt="well known symbols">@@iterator</a>).

    1. [=Check the completion record=] of |method|.

    1. Perform the steps corresponding to the first matching condition below:

        <div class=switch>
        : If |method| is not <span class=esvalue>undefined</span>,
        ::
            1. Let |iter| be [=GetIterator=](|object|, |method|).

            1. [=Check the completion record=] of |iter|.

            1. Repeat:

                1. Let |next| be [=IteratorStep=](|iter|).
                1. [=Check the completion record=] of |next|.
                1. If |next| is false abort this loop.
                1. Let |nextItem| be [=IteratorValue=](next).
                1. [=Check the completion record=] of |nextItem|.
                1. If [=Type=](|nextItem|) is not `Undefined`, `Null` or `Object`,
                    then throw a {{TypeError}} and abort these steps.
                1. Append to |processed keyframes|
                    the result of running the procedure to
                    [=process a keyframe-like object=]
                    passing |nextItem| as the |keyframe input|
                    with the |allow lists| flag set to false.

        : Otherwise,
        ::
            1.  Let |property-indexed keyframe| be
                the result of running the procedure to
                [=process a keyframe-like object=]
                passing |object| as the |keyframe input|
                with the |allow lists| flag set to true.

            1. For each member, |m|, in |property-indexed keyframe|,
                perform the following steps:

                1. Let |property name| be the key for |m|.

                1. If |property name| is
                    "composite", "easing", or "offset",
                    skip the remaining steps in this loop
                    and continue from the next member
                    in |property-indexed keyframe|
                    after |m|.

                1. Let |property values| be
                    the value for |m|.

                1. Let |property keyframes| be
                    an empty sequence of [=keyframes=].

                1. For each value, |v|, in |property values|,
                    perform the following steps:

                    1. Let |k| be a new [=keyframe=]
                        with a `null` [=keyframe offset=].

                    1. Add the property-value pair,
                        |property name| &rarr; |v|,
                        to |k|.

                    1. Append |k| to |property keyframes|.

                1. Apply the procedure to
                    [=compute missing keyframe offsets=]
                    to |property keyframes|.

                1. Add [=keyframes=] in |property keyframes|
                    to |processed keyframes|.

            1. Sort |processed keyframes|
                by the [=computed keyframe offset=] of each [=keyframe=]
                in increasing order.

            1. Merge adjacent [=keyframes=] in |processed keyframes|
                when they have equal [=computed keyframe offsets=].

            1. Let |offsets| be
                 a sequence of [=nullable=] `double` values
                 assigned based on the type of the <code>offset</code> member
                 of the |property-indexed keyframe|
                 as follows:

                <div class=switch>

                : <code>sequence&lt;double?&gt;</code>,
                ::
                    The value of <code>offset</code> as-is.

                : <code>double?</code>,
                ::
                    A sequence of length one
                    with the value of <code>offset</code> as its single item,
                    i.e. &laquo;&nbsp;<code>offset</code>&nbsp;&raquo;,

                </div>

            1. Assign each value in |offsets|
                to the [=keyframe offset=] of the [=keyframe=]
                with the corresponding position in |processed keyframes|
                until the end of either sequence is reached.

            1. Let |easings| be a sequence of {{DOMString}} values
                assigned based on the type of the <code>easing</code> member
                of the |property-indexed keyframe|
                as follows:

                <div class=switch>

                : <code>sequence&lt;DOMString&gt;</code>,
                ::
                    The value of <code>easing</code> as-is.

                : <code>DOMString</code>,
                ::
                    A sequence of length one
                    with the value of <code>easing</code> as its single item,
                    i.e. &laquo;&nbsp;<code>easing</code>&nbsp;&raquo;,

                </div>

            1. If |easings| is an empty sequence,
                let it be a sequence of length one
                containing the single value "linear",
                i.e. &laquo;&nbsp;"linear"&nbsp;&raquo;.

            1. If |easings| has fewer items than |processed keyframes|,
                repeat the elements in |easings| successively
                starting from the beginning of the list
                until |easings| has as many items as |processed keyframes|.

                <div class=example>
                  For example,
                  if |processed keyframes| has five items,
                  and |easings| is the sequence
                  &laquo;&nbsp;"ease-in", "ease-out"&nbsp;&raquo;,
                  |easings| would be repeated to become
                  &laquo;&nbsp;"ease-in", "ease-out", "ease-in", "ease-out", "ease-in"&nbsp;&raquo;.
                </div>

            1. If |easings| has more items than |processed keyframes|,
                store the excess items as |unused easings|.

            1. Assign each value in |easings|
                to a property named <code>easing</code>
                on the [=keyframe=]
                with the corresponding position in |processed keyframes|
                until the end of |processed keyframes| is reached.

            1. If the <code>composite</code> member
                of the |property-indexed keyframe|
                is <em>not</em> an empty sequence:

                1. Let |composite modes| be
                    a sequence of {{CompositeOperationOrAuto}} values
                    assigned from the <code>composite</code> member
                    of |property-indexed keyframe|.
                    If that member is
                    a single {{CompositeOperationOrAuto}} value operation,
                    let |composite modes| be
                    a sequence of length one,
                    with the value of the <code>composite</code>
                    as its single item.

                1. As with |easings|,
                    if |composite modes| has fewer items than |processed keyframes|,
                    repeat the elements in |composite modes| successively
                    starting from the beginning of the list
                    until |composite modes| has as many items
                    as |processed keyframes|.

                1. Assign each value in |composite modes|
                    that is not {{CompositeOperationOrAuto/auto}}
                    to the [=keyframe-specific composite operation=]
                    on the [=keyframe=]
                    with the corresponding position in |processed keyframes|
                    until the end of |processed keyframes| is reached.

        </div>

    1. If |processed keyframes| is not [=loosely sorted by offset=],
        [=throw=] a {{TypeError}} and abort these steps.

    1. If there exist any [=keyframe=] in |processed keyframes|
        whose [=keyframe offset=] is non-null
        and less than zero or greater than one,
        [=throw=] a {{TypeError}} and abort these steps.

    1. For each |frame| in |processed keyframes|,
        perform the following steps:

        1. For each property-value pair in |frame|,
            parse the property value
            using the syntax specified for that property.

            If the property value is invalid
            according to the syntax for the property,
            discard the property-value pair.
            User agents that provide support for diagnosing errors in content
            SHOULD produce an appropriate warning
            highlighting the invalid property value.

        1. Let the [=easing function=] of |frame| be
            the result of parsing the <code>easing</code> property on |frame|
            using the CSS syntax defined for
            the {{EffectTiming/easing}} member of the {{EffectTiming}} dictionary.

            If parsing the <code>easing</code> property fails,
            [=throw=] a {{TypeError}} and abort this procedure.

            Note: Using the CSS parser in both of the above steps
            implies that CSS comments and escaping are allowed,
            but are not retained when the value is successfully parsed.

            Note: In the case where the <code>easing</code> property
            fails to parse,
            it is important that the {{TypeError}} is thrown
            <em>after</em> all reading the properties from |object|
            since failing to do so would be observable
            and will not match the behavior
            if partially open-ended dictionaries are later supported in WebIDL.

    1. Parse each of the values in |unused easings|
        using the CSS syntax defined for
        the {{EffectTiming/easing}} member of the {{EffectTiming}} dictionary,
        and if any of the values fail to parse,
        [=throw=] a {{TypeError}} and abort this procedure.

        <div class=note>

          This final step is needed in order to provide consistent behavior
          such that a {{TypeError}} is thrown
          in all of the following cases:

          <pre highlight=javascript>
            elem.animate({ easing: 'invalid' });
            elem.animate({ easing: ['invalid'] });
            elem.animate([{ easing: 'invalid' }]);
          </pre>

        </div>
  </div>

### The {{KeyframeEffectOptions}} dictionary ### {#the-keyframeeffectoptions-dictionary}

  Additional parameters may be passed to
  the {{KeyframeEffect(target, keyframes, options)}} constructor
  by providing a {{KeyframeEffectOptions}} object.

  <xmp class=idl>
    dictionary KeyframeEffectOptions : EffectTiming {
        CompositeOperation composite = "replace";
        CSSOMString?       pseudoElement = null;
    };
  </xmp>

  <div dfn-type=dict-member class=members
       dfn-for="KeyframeEffectOptions">

  : <dfn>composite</dfn>
  ::
      The [=composite operation=] used
      to composite this animation with the [=effect stack=],
      as specified by one of the {{CompositeOperation}} enumeration values.
      This is used for all [=keyframes=] that specify
      an {{CompositeOperationOrAuto/auto}}
      [=keyframe-specific composite operation=].

  : <dfn>pseudoElement</dfn>
  ::  The [=pseudo-element=] selector (which must be valid or `null`)
      used to specify the [=effect target=] given the [=target element=].

  </div>

The {{CompositeOperation}} and {{CompositeOperationOrAuto}} enumerations {#the-compositeoperation-enumeration}
------------------------------------------------------------------------

  The possible values of an [=keyframe effect=]’s composition behavior
  are represented by the {{CompositeOperation}} enumeration.

  <xmp class=idl>
    enum CompositeOperation { "replace", "add", "accumulate" };
  </xmp>

  <dl dfn-type=enum-value
      dfn-for="CompositeOperation,CompositeOperationOrAuto">

  : <dfn>replace</dfn>
  ::
      Corresponds to the [=composite operation replace|replace=]
      [=composite operation=] value
      such that the [=animation effect=] overrides
      the [=underlying value=] it is combined with.

  : <dfn>add</dfn>
  ::
      Corresponds to the [=composite operation add|add=]
      [=composite operation=] value
      such that the [=animation effect=] is [=value addition|added=] to
      the [=underlying value=] with which it is combined.

  : <dfn>accumulate</dfn>
  ::
      Corresponds to the [=composite operation accumulate|accumulate=]
      [=composite operation=] value
      such that the [=animation effect=] is [=value accumulation|accumulated=]
      onto the [=underlying value=].

  </dl>

  The possible values of a [=keyframe=]'s composition behavior
  share the same values as the {{CompositeOperation}} enumeration
  along with the additional {{CompositeOperationOrAuto/auto}} value.

  <xmp class=idl>
    enum CompositeOperationOrAuto { "replace", "add", "accumulate", "auto" };
  </xmp>


  <dl dfn-type=enum-value
      dfn-for="CompositeOperationOrAuto">
  : <dfn>auto</dfn>
  ::
      Indicates that the [=composite operation=]
      of the associated [=keyframe effect=]
      should be used.

  </dl>

The <code>Animatable</code> interface mixin {#the-animatable-interface-mixin}
-------------------------------------------

  Objects that could be the target of an {{KeyframeEffect}} object
  implement the {{Animatable}} interface mixin.

  <xmp class=idl>
    interface mixin Animatable {
        Animation           animate(object? keyframes,
                                    optional (unrestricted double or KeyframeAnimationOptions) options = {});
        sequence<Animation> getAnimations(optional GetAnimationsOptions options = {});
    };

    dictionary KeyframeAnimationOptions : KeyframeEffectOptions {
        DOMString id = "";
        AnimationTimeline? timeline;
    };

    dictionary GetAnimationsOptions {
        boolean subtree = false;
        CSSOMString? pseudoElement = null;
    };
  </xmp>

  <div dfn-type=method class=methods
       dfn-for="Animatable">

  : <dfn lt="animate(keyframes, options)">Animation animate(|keyframes|, |options|)</dfn>
  ::
      Performs the following steps:

      1. Let |target| be the object on which this method was called.

      1. Construct a new {{KeyframeEffect}} object |effect|
          in the [=relevant Realm=] of |target|
          by using the same procedure as the
          {{KeyframeEffect(target, keyframes, options)}} constructor,
          passing |target| as the |target| argument,
          and the |keyframes| and |options| arguments as supplied.

          If the above procedure causes an exception to be thrown,
          propagate the exception and abort this procedure.

      1. If |options| is a {{KeyframeAnimationOptions}} object,
          let |timeline| be the <code>timeline</code> member of |options|
          or, if <code>timeline</code> member of |options| is missing,
          the [=default document timeline=] of the [=node document=]
          of the element on which this method was called.

      1. Construct a new {{Animation}} object, |animation|,
          in the [=relevant Realm=] of |target|
          by using the same procedure as the {{Animation()}} constructor,
          passing |effect| and |timeline| as arguments of the same name.

      1. If |options| is a {{KeyframeAnimationOptions}} object,
          assign the value of the <code>id</code> member of |options|
          to |animation|'s {{Animation/id}} attribute.

      1. Run the procedure to [=play an animation=] for |animation|
          with the |auto-rewind| flag set to true.

      1. Return |animation|.

      <div class=informative-bg>
      <em>This section is non-normative</em>

        The following code fragment:

        <pre highlight=javascript>
          var animation = elem.animate({ opacity: 0 }, 2000);
        </pre>

        is roughly equivalent to:

        <pre highlight=javascript>
          var effect = new KeyframeEffect(elem, { opacity: 0 }, 2000);
          var animation = new Animation(effect, elem.ownerDocument.timeline);
          animation.play();
        </pre>

      </div>

      <div dfn-type=argument class=parameters
           dfn-for="Animatable/animate(keyframes, options)">

      : <dfn>keyframes</dfn>
      ::
          The [=keyframes=] to use.
          This value is passed to the
          {{KeyframeEffect(target, keyframes, options)}} constructor
          as the |keyframes| parameter
          and has the same interpretation as defined for that constructor.

      : <dfn>options</dfn>
      ::
          The timing and animation options
          for the created {{KeyframeEffect}} and {{Animation}}.

      </div>

  : <dfn lt="getAnimations(options)">sequence&lt;Animation&gt; getAnimations(|options|)</dfn>
  ::
      1. Let |object| be the object on which this method was called.

      1. Let |pseudoElement| be the result of {{KeyframeEffect/pseudo-element parsing}}
          applied to {{GetAnimationsOptions/pseudoElement}} of {{Animatable/getAnimations(options)/options}},
          or `null` if {{Animatable/getAnimations(options)/options}} is not passed.

      1. If |pseudoElement| is not `null`,
          then let |target| be the [=pseudo-element=]
          identified by |pseudoElement|
          with |object| as the originating element.
          Otherwise, let |target| be |object|.

      1. If {{Animatable/getAnimations(options)/options}} is passed
          with {{GetAnimationsOptions/subtree}} set to true,
          then return the set of [=relevant animations for a subtree=] of |target|.
          Otherwise, return the set of [=relevant animations=] for |target|.

      The list returned by the above algorithm is sorted using
      the composite order described for the associated [=animations=]
      of effects in [[#the-effect-stack]].

      Calling this method triggers
      a [=style change event=] for the [=target element=].
      As a result, the returned list reflects the state
      <em>after</em> applying any pending style changes to animation
      such as changes to animation-related style properties
      that have yet to be processed.

      <div dfn-type=argument class=parameters
           dfn-for="Animatable/getAnimations(options)">

      : <dfn>options</dfn>
      ::
          Parameters governing the set of animations
          returned by {{Animatable/getAnimations()}}.

      </div>

  </div>

  <div dfn-type=dict-member class=members>

  : <dfn for=KeyframeAnimationOptions>id</dfn>
  ::
      The string to assign to
      the generated {{Animation}}'s {{Animation/id}} attribute.

  : <dfn for=KeyframeAnimationOptions>timeline</dfn>
  ::
      An optional value which, if present,
      specifies the [=timeline=] with which to associate
      the newly-created [=animation=].

  : <dfn for=GetAnimationsOptions>subtree</dfn>
  ::
      If true, indicates that [=animations=]
      associated with an [=animation effect=]
      whose [=target element=] is a [=descendant=] of the object
      on which {{Animatable/getAnimations()}} is called
      should also be included in the result.

  : <dfn for=GetAnimationsOptions>pseudoElement</dfn>
  ::
      If set, indicates that the target of the operation is the [=pseudo-element=]
      identified by this pseudo selector (e.g. `::before`)
      with the originating element being the object on which the function is called.

  </div>

Extensions to the {{Document}} interface {#extensions-to-the-document-interface}
----------------------------------------

  The following extensions are made to
  the {{Document}} interface defined in [[!DOM]].

  <xmp class=idl>
    partial interface Document {
        readonly attribute DocumentTimeline timeline;
    };
  </xmp>

  <div dfn-type=attribute class=attributes
       dfn-for="Document">

  : <dfn>timeline</dfn>
  ::
      The {{DocumentTimeline}} object representing
      the [=default document timeline=].

  </div>

Extensions to the {{DocumentOrShadowRoot}} interface mixin {#extensions-to-the-documentorshadowroot-interface-mixin}
----------------------------------------------------------

  The following extensions are made to
  the {{DocumentOrShadowRoot}} interface mixin defined in [[!DOM]].

  <xmp class=idl>
    partial interface mixin DocumentOrShadowRoot {
        sequence<Animation> getAnimations();
    };
  </xmp>

  <div dfn-type=method class=methods
       dfn-for="DocumentOrShadowRoot">

  : <dfn lt="getAnimations()">sequence&lt;Animation&gt; getAnimations()</dfn>
  ::
      Returns the set of [=relevant animations for a subtree=]
      for the [=document=] or [=shadow root=]
      on which this method is called.

      The returned list is sorted
      using the composite order described for the associated [=animations=]
      of effects in [[#the-effect-stack]].

      Calling this method triggers a [=style change event=] for the document.
      As a result, the returned list reflects the state
      <em>after</em> applying any pending style changes to animation
      such as changes to animation-related style properties
      that have yet to be processed.

  </div>


Extensions to the {{Element}} interface {#extensions-to-the-element-interface}
----------------------------------------

  Since DOM Elements can be the target of an animation,
  the {{Element}} interface [[!DOM]] is extended as follows:

  <xmp class=idl>
    Element includes Animatable;
  </xmp>

  This allows the following kind of usage.

  <div class=example>
    <pre highlight=javascript>
      elem.animate({ color: 'red' }, 2000);
    </pre>
  </div>


The {{AnimationPlaybackEvent}} interface {#the-animationplaybackevent-interface}
----------------------------------------

  [=Animation playback events=] are represented using the
  {{AnimationPlaybackEvent}} interface.

  <xmp class=idl>
    [Exposed=Window]
    interface AnimationPlaybackEvent : Event {
        constructor(DOMString type, optional AnimationPlaybackEventInit eventInitDict = {});
        readonly attribute double? currentTime;
        readonly attribute double? timelineTime;
    };
    dictionary AnimationPlaybackEventInit : EventInit {
        double? currentTime = null;
        double? timelineTime = null;
    };
  </xmp>

  <div dfn-type=constructor class=constructors
       dfn-for="AnimationPlaybackEvent">

  : <dfn lt="AnimationPlaybackEvent(type, eventInitDict)">
      AnimationPlaybackEvent (<var ignore>type</var>, <var ignore>eventInitDict</var>)</dfn>
  ::
      Constructs a new {{AnimationPlaybackEvent}} object
      using the procedure defined for [=constructing events=] [[!DOM]].

  </div>

  <div dfn-type=attribute class=attributes
       dfn-for="AnimationPlaybackEvent">

  : <dfn>currentTime</dfn>
  ::
      The [=animation/current time=]
      of the [=animation=] that generated the event
      at the moment the event was queued.
      This will be `null`
      if the [=animation=] was [=play state/idle=]
      at the time the event was generated.

  : <dfn attribute for=AnimationPlaybackEvent>timelineTime</dfn>
  ::
      The [=time value=] of the [=timeline=]
      with which the [=animation=] that generated the event is associated
      at the moment the event was queued.
      This will be `null`
      if the [=animation=] was not associated with an [=active timeline=]
      at the time the event was queued.

  </div>

  <div dfn-type=dict-member class=members
       dfn-for=AnimationPlaybackEventInit>

  : <dfn>currentTime</dfn>
  ::
      See the description of the {{AnimationPlaybackEvent/currentTime}} attribute.

  : <dfn>timelineTime</dfn>
  ::
      See the description of the {{AnimationPlaybackEvent/timelineTime}} attribute.

  </div>

Model liveness {#model-liveness}
--------------

  Changes made to any part of the model
  cause the entire timing model to be updated
  and any dependent style.

  Unless otherwise stated,
  invoking the methods or constructors,
  or getting or setting the members
  of interfaces defined in the [=Web Animations API=]
  does <em>not</em> produce a [=style change event=].

  Note: Other specifications that extend this specification
  are expected to refine the requirements on [=style change events=]
  by introducing circumstances where such events <em>are</em> triggered.
  For example,
  when the interfaces in this specification represent
  animations defined by CSS markup,
  many of their methods will need to trigger [=style change events=]
  in order to reflect changes to the specified style.

<div class=informative-bg>
<em>This section is non-normative</em>

  Based on the above requirement
  and normative requirements elsewhere in this specification,
  the following invariants can be observed:

  : Changes made to the [=Web Animations model=] take effect immediately
  ::
      For example, if the {{KeyframeEffect}} associated with an {{Animation}}
      is [=seeked=] (see [[#setting-the-current-time-of-an-animation]])
      via the [=Web Animations API=],
      the value returned when querying the animation's <code>startTime</code>
      will reflect updated state of the model immediately.

      <div class=example>
        <pre highlight=javascript>
          // Initially animation.effect.getComputedTiming().localTime is 3000
          animation.currentTime += 2000;
          alert(animation.effect.getComputedTiming().localTime); // Displays "5000"
        </pre>
       </div>

  : Querying the computed style of a property affected by animation
      returns the fully up-to-date state of the animation
  ::
      For example, if the used style of an element is queried
      immediately after applying a new {{Animation}} to that element,
      the result of the new animation will be incorporated
      in the value returned.

      <div class=example>
        <pre highlight=javascript>
          // Set opacity to 0 immediately
          elem.animate({ opacity: 0 }, { fill: 'forwards' });
          alert(window.getComputedStyle(elem).opacity); // Displays "0"
        </pre>
      </div>

  : Changes made within the same task are synchronized
      such that the whole set of changes is rendered together
  ::
      As a result of changes to the model taking effect immediately
      combined with ECMAScript's run-to-completion semantics,
      there should never be a situation where, for example,
      <em>only</em> the changes to specified style are rendered
      without applying animation.

      <div class=example>
        <pre highlight=javascript>
          // Fade the opacity with fallback for browsers that don't
          // support Element.animate
          elem.style.opacity = '0';
          elem.animate([ { opacity: 1 }, { opacity: 0 } ], 500);
        </pre>
      </div>

      Note, however, that in the example above,
      a user agent may render a frame
      with <em>none</em> of the above changes applied.
      This might happen, for example,
      if rendering occurs in a separate process
      that is scheduled to run shortly after the above task completes
      but before the changes can be communicated to the process.

  : The value returned by
      the <code>currentTime</code> attribute of a [=document timeline=]
      will not change within a task
  ::
      Due to the requirement on [=timelines=]
      to update their [=timeline/current time=]
      each time the [=update animations and send events=] procedure is run,
      querying the <code>currentTime</code> twice
      within a long block of code that is executed in the same script block
      will return the same value as shown in the following example.

      <div class=example>
        <pre highlight=javascript>
          var a = document.timeline.currentTime;
          // ... many lines of code ...
          var b = document.timeline.currentTime;
          alert(b - a); // Displays 0
        </pre>
      </div>

  : The time passed to a <code>requestAnimationFrame</code> callback
      will be equal to <code>document.timeline.currentTime</code>
  ::
      Since HTML's [=event loop processing model=] defines
      that the procedure to [=update animations and send events=]
      is performed prior to
      [=run the animation frame callbacks|running animation frame callbacks=],
      and since the time passed to such callbacks
      is the same |now| timestamp is passed to both procedures,
      the [=timeline/current time=] of a the [=default document timeline=]
      should match the time passed to <code>requestAnimationFrame</code>.

      <div class=example>
        <pre highlight=javascript>
          window.requestAnimationFrame(function(now) {
            // Displays 0
            alert(now - document.timeline.currentTime);
          });
        </pre>
      </div>

  : Calling methods from this programming interface
      will generally <em>not</em> cause transitions to be triggered

  ::
      Consider the following example:

      <div class=example>
        <pre highlight=javascript>
          // Setup transition start point
          div.style.opacity = '1';
          getComputedStyle(div).opacity;

          // Setup transition end point
          div.style.transition = 'opacity 1s';
          div.style.opacity = '0';

          // Fire an animation
          div.animate({ opacity: [0.5, 1] }, 500);

          // Wait for the transition to end -- the following will never be called!
          div.addEventListener('transitionend', () => {
            console.log('transitionend');
          });
        </pre>
      </div>

      In this case, calling {{Animatable/animate()}}
      will <em>not</em> trigger a [=style change event=].
      As a result, the pending style change
      will be processed at the same time as
      the style change resulting from the new animation.
      Since the animation style will override
      the [=before-change style=] and the [=after-change style=],
      no transition will be generated
      and the event handler for the [=transitionend=] event
      will never be called.

</div>


Integration with Media Fragments {#integration-with-media-fragments}
================================

  The Media Fragments specification [[!MEDIA-FRAGS]]
  defines a means for addressing a temporal range of a media resource.
  The application of media fragments depends on the MIME type
  of the resource on which they are specified.
  For resources with the [=SVG MIME type=] [[!SVG11]],
  the application of temporal parameters is defined
  in the <a href="https://svgwg.org/specs/animation-elements/">Animation Elements</a> specification.

  Note: Media fragments are defined to operate on resources
  based on their MIME type.
  As a result, temporal addressing might not be supported
  in all situations where Web Animations content is used.

Interaction with page display {#interaction-with-page-display}
=============================

  HTML permits user agents to store
  [=an entry with persisted user state|user-agent defined state=]
  along with a [=session history entry=]
  so that as a user navigates between pages,
  the previous state of the page can be restored
  including state such as scroll position [[HTML]].

  User agents that pause and resume [=media elements=]
  when the referencing document is unloaded and traversed,
  are encouraged to apply consistent handling
  to documents containing Web Animations content.
  If provided, this behavior SHOULD be achieved
  by adjusting the [=time values=] of any [=timelines=]
  that track wallclock time.

  Issue(2083): Is this at odds with
  those [=time values=] being relative to <code>navigationStart</code>
  and with <code>requestAnimationFrame</code> using the same time
  as <code>document.timeline.currentTime</code>?

Implementation requirements {#implementation-requirements}
===========================

Precision of time values {#precision-of-time-values}
------------------------

  The internal representation of time values
  is implementation dependent.
  However, it is RECOMMENDED that user agents be able
  to represent input time values with microsecond precision
  so that a [=time value=] (which nominally represents milliseconds)
  of 0.001 is distinguishable from 0.0.

Conformance criteria {#conformance-criteria}
--------------------

  This specification defines an abstract model for animation
  and, as such, for user agents that do not support scripting,
  there are no conformance criteria
  since there is no testable surface area.

  User agents that do not support scripting, however,
  may implement additional technologies
  defined in terms of this specification,
  in which case the definitions provided in this specification
  will form part of the conformance criteria
  of the additional technology.

  A <dfn export>conforming scripted Web Animations user agent</dfn>
  is a user agent that implements
  the [=Web Animations API=]
  defined in [[#programming-interface]].

Acknowledgements {#acknowledgements}
================

  Thank you to Steve Block, Michael Giuffrida, Ryan Seys, and Eric Willigers
  for their contributions to this specification.

  Thank you also to Michiel “Pomax” Kamermans
  for help with the equations for a proposed smooth easing function,
  although this feature has been deferred to a subsequent specification.

  Our deep gratitude goes out to
  <a href="http://www.endemolshine.com.au">Southern Star Animation</a>
  for their kind generosity and patience in introducing the editors
  to the processes and techniques used in producing broadcast animations.

Changes since last publication {#changes-since-last-publication}
==============================

  The following changes have been made since the
  <a href="https://www.w3.org/TR/2023/WD-web-animations-1-20230605/">5 June 2023 Working Draft</a>:

  (Nothing yet)

  The <a href="https://github.com/w3c/csswg-drafts/commits/main/web-animations-1">changelog</a>
  provides a more detailed history.

Appendix A: Animation types of existing properties {#animation-types}
==================================================

  Typically the [=animation type=] of a property
  is included along with its definition.
  However, for some properties defined in older or very mature specifications
  the [=animation type=] information is not included.
  All such properties are assumed to have
  an [=animation type=] of [=by computed value=]
  unless they are one of the exceptions listed below.

  <wpt>
    animation-model/animation-types/accumulation-per-property-001.html
    animation-model/animation-types/accumulation-per-property-002.html
    animation-model/animation-types/addition-per-property-001.html
    animation-model/animation-types/addition-per-property-002.html
    animation-model/animation-types/discrete.html
    animation-model/animation-types/interpolation-per-property-001.html
    animation-model/animation-types/interpolation-per-property-002.html
    animation-model/animation-types/scrollbar-interpolation.html
    animation-model/animation-types/visibility.html
  </wpt>

Animation of 'font-weight' {#animating-font-weight}
--------------------------

  The 'font-weight' property values prior to Level 4 are
  [[css-values-4#combining-values|combined]] as follows:

  * [=Interpolated=] via discrete steps (multiples of 100).
      The interpolation happens in real number space as for <<number>>s,
      and is converted to an integer by rounding to the nearest multiple of 100,
      with values halfway between multiples of 100
      rounded towards positive infinity.

  * [=value addition|Addition=] of 'font-weight' values is defined as
      <var ignore>V<sub>result</sub></var> =
        <var ignore>V<sub>a</sub></var> + <var ignore>V<sub>b</sub></var>

  Note: This definition is obsoleted by [[CSS-FONTS-4]] where
  the requirement that a 'font-weight' value be a multiple of 100 is dropped.
  At that point the [=animation type=] for 'font-weight' is simply
  [=by computed value=].

Animation of 'visibility' {#animating-visibility}
-------------------------

  For the 'visibility' property,
  ''visibility/visible'' is [=interpolated=] as a discrete step
  where values of <var ignore>p</var> between 0 and 1
  map to ''visibility/visible''
  and other values of <var ignore>p</var>
  map to the closer endpoint.
  If neither value is ''visibility/visible'', then [=discrete=] animation is used.

Animation of 'box-shadow' and 'text-shadow' {#animating-shadow-lists}
-------------------------------------------

  Animation the 'box-shadow' or 'text-shadow' property
  follows the procedures for [[css-values-4#combining-values|combining]]
  <dfn export lt="combining shadow lists" local-lt="shadow lists">shadow lists</dfn>
  as follows:

  Each shadow in the list
  (treating ''shadow/none'' as a 0-length list)
  is interpolated component-wise as with [=by computed value=] behavior.
  However, if both input shadows are ''shadow/inset''
  or both input shadows are not ''shadow/inset'',
  then the interpolated shadow must match the input shadows in that regard.
  If any pair of input shadows has one ''shadow/inset''
  and the other not ''shadow/inset'',
  the entire shadow-list uses [=discrete=] animation.
  If the lists of shadows have different lengths,
  then the shorter list is padded at the end
  with shadows whose color is ''transparent'',
  whose lengths are all ''0'',
  and whose ''shadow/inset'' (or not) matches the longer list.

  [=value addition|Addition=] of two [=shadow lists=]
  <var>V<sub>a</sub></var> and <var>V<sub>b</sub></var>
  is defined as [=list=] concatenation
  such that <var ignore>V<sub>result</sub></var>
  is equal to <var>V<sub>a</sub></var>
  [=extended=] with <var>V<sub>b</sub></var>.

  [=value accumulation|Accumulation=] of [=shadow lists=]
  follows the matching rules for interpolation above,
  performing addition on each component according to its type,
  or falling back to [=discrete=] animation
  if the ''shadow/inset'' values do not match.

  Privacy Considerations {#priv}
===============================================

No privacy considerations have been reported on this module.

Security Considerations {#sec}
===============================================

No security considerations have been reported on this module.

<wpt ignore title="non-specific crashers">
  animation-model/keyframe-effects/effect-on-marquee-parent-crash.html
  animation-model/keyframe-effects/transform-and-opacity-on-inline-001.html
  crashtests/color-mix-crashtest.html
  crashtests/effectively-infinite-timing-parameters.html
  crashtests/get-computed-timing-crash.html
  crashtests/get-keyframe-fontsize-crash.html
  crashtests/get-timing-bad-pseudo-crash.html
  crashtests/infinite-active-duration.html
  crashtests/non-interpolable-transition.html
  crashtests/partially-overlapping-animations-one-not-current-001.html
  crashtests/reparent-animating-element-001.html
  crashtests/reparent-animating-element-002.html
  crashtests/set-timeline-undefined-progress.html
  crashtests/sibling-index-offset-crash.html
  interfaces/Animation/commitStyles-crash.html
  interfaces/Animation/commitStyles-svg-crash.html
</wpt>